MongoDB学习笔记3:创建,更新及删除文档

1. 插入并保存文档

    插入是向MongoDB中添加数据的基本方法。对目标集使用insert方法,插入一个文档:

> db.foo.insert({"bar" : "baz"})
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("55062bcad94d123625069ca4"), "bar" : "baz" }
    这个操作会给文档增加一个“_id”键(要是原来没有的话),然后将其保存到MongoDB中。

1. 批量插入

优势:一次批量插入只是单个TCP请求,避免了许多零碎的请求所带来的开销。

2. 插入:原理和作用

1. 插入时,驱动程序会将数据转换为BSON的形式。

2. 数据库解析BSON,只检验是否包含"_id"键并且文档不超过4MB。

副作用: 允许插入无效的数据

好处: 让数据库更加安全,远离注入式攻击

2. 删除文档

    使用remove进行永久性的删除。

> db.foo.find()
{ "_id" : ObjectId("550631a5d94d123625069ca8"), "bar" : "foo" }
{ "_id" : ObjectId("550631b0d94d123625069ca9"), "bar" : "foo" }
{ "_id" : ObjectId("550631b3d94d123625069caa"), "bar" : "foo1" }
{ "_id" : ObjectId("550631b7d94d123625069cab"), "bar" : "foo2" }
> db.foo.remove({"bar" : "foo"})
WriteResult({ "nRemoved" : 2 })
> db.foo.remove({})
WriteResult({ "nRemoved" : 2 })
> db.foo.find()
> 

删除速度:

test.py:

import pymongo
import time
connection = pymongo.Connection("localhost", 27017)

db = connection.test_database
for i in range(1000000):
	db.test_collection.insert({"foo" : i})

start = time.time()
db.test_collection.remove({})

total = time.time() - start
print "%d seconds" % total
删除时间为0s.

3. 更新文档

    文档存入数据库以后,就可以使用update方法来修改它。update有两个参数,一个是查询文档,用来找出要更新的文档,另一个是修改器文档,描述对找到的文档做哪些修改。

1. 文档替换(更新全部)

    整个文档的替换过程中,我们要找到唯一的键值作为筛选的标准。假设我们要将:

MongoDB学习笔记3:创建,更新及删除文档_第1张图片

变成:

MongoDB学习笔记3:创建,更新及删除文档_第2张图片

    则我们需要这样做:

> db.users.insert({"name" : "joe", "friends" : 32, "enemies" : 2})
WriteResult({ "nInserted" : 1 })
> var joe = db.users.findOne({"name" : "joe"})
> joe.relationships = {"friends" : joe.friends, "enemies" : joe.enemies}
{ "friends" : 32, "enemies" : 2 }
> joe.username = joe.name
joe
> delete joe.friends
true
> delete joe.enemies
true
> delete joe.name
true
> db.users.find()
{ "_id" : ObjectId("550646922a18d2707db456a1"), "name" : "joe", "friends" : 32, "enemies" : 2 }
> joe
{
	"_id" : ObjectId("550646922a18d2707db456a1"),
	"relationships" : {
		"friends" : 32,
		"enemies" : 2
	},
	"username" : "joe"
}
> db.users.update({"name" : "joe"}, joe)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find()
{ "_id" : ObjectId("550646922a18d2707db456a1"), "relationships" : { "friends" : 32, "enemies" : 2 }, "username" : "joe" }
    但是,假设有多个{“name”:"joe"}就麻烦了:
> db.people.find()
{ "_id" : ObjectId("5506482d2a18d2707db456a3"), "name" : "joe", "age" : 65 }
{ "_id" : ObjectId("550648302a18d2707db456a4"), "name" : "joe", "age" : 20 }
{ "_id" : ObjectId("550648352a18d2707db456a5"), "name" : "joe", "age" : 49 }
> joe = db.people.findOne({"name" : "joe", "age" : 20})
{ "_id" : ObjectId("550648302a18d2707db456a4"), "name" : "joe", "age" : 20 }
> joe.age++
20
> db.people.update({"name" : "joe", "age" : 20}, joe)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.people.find()
{ "_id" : ObjectId("5506482d2a18d2707db456a3"), "name" : "joe", "age" : 65 }
{ "_id" : ObjectId("550648302a18d2707db456a4"), "name" : "joe", "age" : 21 }
{ "_id" : ObjectId("550648352a18d2707db456a5"), "name" : "joe", "age" : 49 }
    这里,我们必须编写:
> db.people.update({"name" : "joe", "age" : 20}, joe)
    而不能草率的写成:
> db.people.update({"name" : "joe"}, joe)
因为这样会找到age为65的joe,但是由于id不一致,导致会update失败。

2. 使用修改器

    通常文档只有一部分要更新。利用原子的更新修改器,可以使得这种部分更新极为高效。更新修改器是种特殊的键,用来指定复杂的更新操作。

    假设我们访问一个网址要递增访问次数:

> db.analytics.find()
{ "_id" : ObjectId("55064a722a18d2707db456a6"), "url" : "www.example.com", "pageviews" : 52 }
> db.analytics.update({"url" : "www.example.com"}, {"$inc": {"pageviews" : 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.analytics.find()
{ "_id" : ObjectId("55064a722a18d2707db456a6"), "url" : "www.example.com", "pageviews" : 53 }

1. “$set”修改器入门

    $set用来指定一个键的值。如果这个键不存在,则创建它。例如,用户资料存储在下面这样的文档里:

> db.users.findOne()
{
	"_id" : ObjectId("55064d5c2a18d2707db456a7"),
	"name" : "joe",
	"age" : 30,
	"sex" : "male",
	"location" : "wisconsin"
}
    假设我们向把喜欢的书籍添加进去,则可以用$set:
> db.users.update({"_id" : ObjectId("55064d5c2a18d2707db456a7")}, {$set : {"favorite book" : "war and peace"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
	"_id" : ObjectId("55064d5c2a18d2707db456a7"),
	"name" : "joe",
	"age" : 30,
	"sex" : "male",
	"location" : "wisconsin",
	"favorite book" : "war and peace"
}
因为_id具有唯一的标志,所以建议使用_id而非使用{“name” : "joe"}。

    假设我们喜欢的实际上是另一本书,那么我们依旧可以使用$set:

> db.users.update({"_id" : ObjectId("55064d5c2a18d2707db456a7")}, {$set : {"favorite book" : "green eggs and ham"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
	"_id" : ObjectId("55064d5c2a18d2707db456a7"),
	"name" : "joe",
	"age" : 30,
	"sex" : "male",
	"location" : "wisconsin",
	"favorite book" : "green eggs and ham"
}
    而如果我们喜欢的一堆书,那么可以将$set的值变成列表(通常使用$push进行列表的插入,后面介绍)

    也可以使用"$set"修改内嵌文档:


> db.blog.posts.insert({"title" : "A Blog Post", "content" : "...", "author" : {"name" : "joe", "email" : "[email protected]"}})
WriteResult({ "nInserted" : 1 })
> db.blog.posts.update({"author.name" : "joe"}, {"$set" : {"author.name" : "joe schmoe"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.posts.find()
{ "_id" : ObjectId("550668e2c0e0d2cfc19edb82"), "title" : "A Blog Post", "content" : "...", "author" : { "name" : "joe schmoe", "email" : "[email protected]" } }


2. 增加和减少

    “$inc”修改器用来增加已有键的值,或者在键不存在时创建一个键。


> db.foo.insert({"url" : "www.example.com", "pageviews" : 1})
WriteResult({ "nInserted" : 1 })
> db.foo.update({"url" : "www.example.com"}, {"$inc" : {"pageviews" : 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : ObjectId("55066b30c0e0d2cfc19edb89"), "url" : "www.example.com", "pageviews" : 2 }


3. 数组修改器

    如果指定的键已经存在,"$push"会向已有的数组末尾加入一个元素,要是没有就会创建一个新的数组。例如向博客文章添加评论:


> db.blog.posts.insert({"title" : "A blog post", "content" : "..."})
WriteResult({ "nInserted" : 1 })
> db.blog.posts.update({"title" : "A blog post"}, {$push : {"comments" : {"name" : "joe", "email" : "[email protected]", "content" : "nice post."}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.posts.update({"title" : "A blog post"}, {$push : {"comments" : {"name" : "bob", "email" : "[email protected]", "content" : "good post."}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.posts.findOne()
{
	"_id" : ObjectId("55066dbbc0e0d2cfc19edb8b"),
	"title" : "A blog post",
	"content" : "...",
	"comments" : [
		{
			"name" : "joe",
			"email" : "[email protected]",
			"content" : "nice post."
		},
		{
			"name" : "bob",
			"email" : "[email protected]",
			"content" : "good post."
		}
	]
}
而使用$addToSet可以插入不重复的数据:



> db.users.insert({"username" : "joe", "emails" : ["[email protected]", "[email protected]", "[email protected]"]})
WriteResult({ "nInserted" : 1 })
> db.users.update({"username" : "joe"}, {$addToSet : {"emails" : "[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
> db.users.update({"username" : "joe"}, {$addToSet : {"emails" : "[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
	"_id" : ObjectId("55066eb1c0e0d2cfc19edb8c"),
	"username" : "joe",
	"emails" : [
		"[email protected]",
		"[email protected]",
		"[email protected]",
		"[email protected]"
	]
}
    假设一次添加多个邮箱,则将“$addToSet”和"$each"结合起来即可:



> db.users.update({"username" : "joe"}, {$addToSet : {"emails" : {$each : ["[email protected]", "[email protected]"]}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
	"_id" : ObjectId("55066eb1c0e0d2cfc19edb8c"),
	"username" : "joe",
	"emails" : [
		"[email protected]",
		"[email protected]",
		"[email protected]",
		"[email protected]",
		"[email protected]"
	]
}
    我们可以使用$pop这个修改器从数组任何一端删除元素。{$pop : {key : 1}}从数组末尾删除一个元素,{$pop : {key : -1}}则从头部删除。



> db.users.remove({})
WriteResult({ "nRemoved" : 1 })
> db.users.insert({"name" : "joe", "num" : [1, 2, 3]})
WriteResult({ "nInserted" : 1 })
> db.users.update({"name" : "joe"}, {$pop : {"num" : 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find()
{ "_id" : ObjectId("550670d5c0e0d2cfc19edb8d"), "name" : "joe", "num" : [ 1, 2 ] }
> db.users.update({"name" : "joe"}, {$pop : {"num" : -1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find()
{ "_id" : ObjectId("550670d5c0e0d2cfc19edb8d"), "name" : "joe", "num" : [ 2 ] }
> 
而$pull会将所有匹配的部分全部删除:



> db.users.remove({})
WriteResult({ "nRemoved" : 1 })
> db.users.insert({"name" : "joe", "num" : [1, 2, 3, 1, 1]})
WriteResult({ "nInserted" : 1 })
> db.users.update({"name" : "joe"}, {$pull : {"num" : 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find()
{ "_id" : ObjectId("55067174c0e0d2cfc19edb8e"), "name" : "joe", "num" : [ 2, 3 ] }


4. 数组的定位修改器

    若是数组有多个值,而我们只想对其中的一部分进行操作,则:通过位置或者定位操作符。


> db.blog.posts.findOne()
{
	"_id" : ObjectId("55066dbbc0e0d2cfc19edb8b"),
	"title" : "A blog post",
	"content" : "...",
	"comments" : [
		{
			"name" : "joe",
			"email" : "[email protected]",
			"content" : "nice post.",
			"votes" : 0
		},
		{
			"name" : "bob",
			"email" : "[email protected]",
			"content" : "good post.",
			"votes" : 0
		}
	]
}
> db.blog.posts.update({"title" : "A blog post"}, {$inc : {"comments.0.votes" : 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.posts.findOne()
{
	"_id" : ObjectId("55066dbbc0e0d2cfc19edb8b"),
	"title" : "A blog post",
	"content" : "...",
	"comments" : [
		{
			"name" : "joe",
			"email" : "[email protected]",
			"content" : "nice post.",
			"votes" : 1
		},
		{
			"name" : "bob",
			"email" : "[email protected]",
			"content" : "good post.",
			"votes" : 0
		}
	]
}
    这里comments.0.votes代表数组的第一个元素,0为索引。


    而$的作用是:将定位已经匹配的元素:


> db.blog.posts.update({"comments.name" : "bob"}, {$set : {"comments.$.name" : "Bob"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.posts.findOne()
{
	"_id" : ObjectId("55066dbbc0e0d2cfc19edb8b"),
	"title" : "A blog post",
	"content" : "...",
	"comments" : [
		{
			"name" : "joe",
			"email" : "[email protected]",
			"content" : "nice post.",
			"votes" : 1
		},
		{
			"name" : "Bob",
			"email" : "[email protected]",
			"content" : "good post.",
			"votes" : 0
		}
	]
}


3. upsert

    upsert是一种特殊的更新。要是没有文档符合更新条件,就会以这个条件和更新文档为基础创建一个新的文档。如果找到了匹配的文档,则正常更新。(第三个参数为true则代表upsert)


> db.math.remove({})
WriteResult({ "nRemoved" : 0 })
> db.math.update({"count" : 25}, {"$inc" : {"count" : 3}}, true)
WriteResult({
	"nMatched" : 0,
	"nUpserted" : 1,
	"nModified" : 0,
	"_id" : ObjectId("550677f5312f793834187ab9")
})
> db.math.findOne()
{ "_id" : ObjectId("550677f5312f793834187ab9"), "count" : 28 }
    save可以在文档不存在时插入,存在时更新。它只有一个参数:文档。要是这个文档含有“_id”键,save会调用upsert。否则,会调用插入。



> var x = db.foo.findOne()
> x
{
	"_id" : ObjectId("55066b30c0e0d2cfc19edb89"),
	"url" : "www.example.com",
	"pageviews" : 2
}
> x.num = 42
42
> db.foo.save(x)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> x
{
	"_id" : ObjectId("55066b30c0e0d2cfc19edb89"),
	"url" : "www.example.com",
	"pageviews" : 2,
	"num" : 42
}


4. 更新多个文档

    默认情况下,更新只能对符合匹配条件的第一个文档执行操作。要是多个文档符合条件,其余的文档就没有变化。要使得所有匹配到的文档都得到更新,可以设置update的第四个参数为true。


> db.foo.find()
{ "_id" : ObjectId("55067bd1c0e0d2cfc19edb93"), "name" : "joe", "age" : 1 }
{ "_id" : ObjectId("55067bd4c0e0d2cfc19edb94"), "name" : "joe", "age" : 2 }
{ "_id" : ObjectId("55067bd7c0e0d2cfc19edb95"), "name" : "joe", "age" : 3 }
> db.foo.update({"name" : "joe"}, {$set : {"wish" : "hello world"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : ObjectId("55067bd1c0e0d2cfc19edb93"), "name" : "joe", "age" : 1, "wish" : "hello world" }
{ "_id" : ObjectId("55067bd4c0e0d2cfc19edb94"), "name" : "joe", "age" : 2 }
{ "_id" : ObjectId("55067bd7c0e0d2cfc19edb95"), "name" : "joe", "age" : 3 }
> db.foo.update({"name" : "joe"}, {$set : {"wish" : "hello world"}}, false, true)
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })
> db.foo.find()
{ "_id" : ObjectId("55067bd1c0e0d2cfc19edb93"), "name" : "joe", "age" : 1, "wish" : "hello world" }
{ "_id" : ObjectId("55067bd4c0e0d2cfc19edb94"), "name" : "joe", "age" : 2, "wish" : "hello world" }
{ "_id" : ObjectId("55067bd7c0e0d2cfc19edb95"), "name" : "joe", "age" : 3, "wish" : "hello world" }



你可能感兴趣的:(MongoDB学习笔记3:创建,更新及删除文档)