2.MongoDB CRUD

906 阅读10分钟

1.INSERT 插入

  • 假设插入10条数据,第7条失败,则前6条插入成功,789不会成功。
  • mongodb制作基本检查不超过16mb即可,插入非法数据很容易,注意只给信任的应用使用。
  • 主流语言的驱动程序,对数据插入时候做校验。比如文档是否过大,文档是否包含非utf8的字符串,是否使用不可识别的类型。

1.1.db.collection.insertOne() 向集合中插入一条新文档。

db.ins.insertOne({name:'four doc',age:'4',tag:'four insert doc'})
返回结果
{
"acknowledged" : true,
"insertedId" : ObjectId("5c85f85806bbda89cc0dc44a")
}

1.2.db.collection.insertMany() 在集合中插入多个新文档。

操作
db.ins.insertMany([
{name:'five doc',age:'5',tag:'five insert doc'},
{name:'six doc',age:'7',tag:'six insert doc'},
{name:'seven doc',age:'8',tag:'seven insert doc'}
])
返回结果
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5c85f93806bbda89cc0dc44b"),
ObjectId("5c85f93806bbda89cc0dc44c"),
ObjectId("5c85f93806bbda89cc0dc44d")
]
}

1.3.db.collection.insert() 在集合中插入1条或多条文档(6.0抛弃,但还可用)

单条操作
db.ins.insert({name:'frist doc',age:'1',tag:'frist insert doc'})
返回结果:
WriteResult({ "nInserted" : 1 })
多条操作:
db.ins.insert([
{name:'sec doc',age:'2',tag:'sec insert doc'},
{name:'thr doc',age:'3',tag:'thr insert doc'}
])
返回结果:
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

1.4.其他可以实现插入的操作

db.collection.update() 当upsert为true时//第三个参数 db.collection.updateOne() 当upsert为true时//第三个参数 db.collection.updateMany() 当upsert为true时//第三个参数 db.collection.findAndModify() 当upsert为true时** db.collection.findAndModify() 当upsert为true时** db.collection.findOneAndReplace() 当upsert为true时


2.UPDATE 更新

  • $set 新增键和更新键(可以理解为mysql增加字段更新字段)
  • $unset删除键(可以理解为mysql删除字段)
  • $incr 键的值增减和减少,键的值只能是数字,键的类型只能是整型长整型或双精度浮点型不可是其他类型。
  • $push 对数组的末尾添加元素

2.1 db.collection.update 更新记录

插入测试数据

db.inventory.insertMany( [
{ item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
{ item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
{ item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }
]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5cbd706b35bc4d3801a312d1"),
ObjectId("5cbd706b35bc4d3801a312d2"),
....
....
]
}

2.2 db.collection.updateOne() 更新第一个符合条件的文档

更新前
db.inventory.find({item:"paper"})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0106"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }

执行更新命令,会更新第一个符合条件的文档
db.inventory.updateOne(
{ item: "paper" },
{
 $set: { "size.uom": "cm", status: "P" },
 $currentDate: { lastModified: true }
})
结果,匹配到一条,修改一条
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

更新后
db.inventory.find({item:"paper"})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "cm" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:38:32.820Z") }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0106"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }

2.3 db.collection.updateMany() 更新多条文档,如果upsert为true且文档不存在则插入文档

更新前
db.inventory.find({qty:{$lt:50}}) 
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" } 
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc452"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "status" : "A" } 
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0102"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" } 
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0104"), "item" : "mousepad", "qty" : 25, "size" : { "h" : 19, "w" : 22.85, "uom" : "cm" }, "status" : "P" } 
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0108"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "status" : "A" } 

执行更新命令
db.inventory.updateMany(
{ "qty": { $lt: 50 } },
{
  $set: { "size.uom": "in", status: "P" },
  $currentDate: { lastModified: true }
}
)

结果,匹配到5条文档,修改5条文档
{ "acknowledged" : true, "matchedCount" : 5, "modifiedCount" : 5 }
更新后
db.inventory.find({qty:{$lt:50}})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "in" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:41:16.569Z") }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc452"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "in" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:41:16.570Z") }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0102"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "in" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:41:16.570Z") }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0104"), "item" : "mousepad", "qty" : 25, "size" : { "h" : 19, "w" : 22.85, "uom" : "in" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:41:16.570Z") }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0108"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "in" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:41:16.570Z") }

2.4 db.collection.replaceOne() 替换第一条符合条件的文档,并将新参数传递给replaceOne,不能替换ID字段。

更新前
db.inventory.find({item:"paper"}) 
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "cm" }, "status" : "P", "lastModified" : ISODate("2019-03-11T08:38:32.820Z") } 
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0106"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" } 

执行更新命令
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
 )

结果,匹配1条文档,修改1条文档
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

更新后
db.inventory.find({item:"paper"})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "instock" : [ { "warehouse" : "A", "qty" : 60 }, { "warehouse" : "B", "qty" : 40 } ] }
{ "_id" : ObjectId("5c861b4b274c7c6eff9c0106"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }	

将当前集合的文档转换为子文档(嵌套文档)
db.inventory.find()
{ "_id" : ObjectId("5fd07c9198ada1ce0d1e52a5"), "name" : "joe", "friends" : 32, "enemies" : 2 }
   
db.inventory.replaceOne(
{'name':'joe'},
{'name':'joe','relationships':{"friends" : 32,"enemies" : 2}}
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

db.inventory.find()
{ "_id" : ObjectId("5fd07c9198ada1ce0d1e52a5"), "name" : "joe", "relationships" : { "friends" : 32, "enemies" : 2 } }
bill-repli:PRIMARY> 


2.5 db.collection.updateONE,updateMany,updateReplace 当upsert为true且记录不存在则插入新纪录

try {
   db.inventory.updateOne(
 { "name" : "Pizza Rat's Pizzaria" },
 { $set: {"_id" : 4, "violations" : 7, "borough" : "Manhattan" } },
 { upsert: true }
  );
   } catch (e) {
print(e);
   }
结果:因为没有匹配这条记录的条件。所以插入了一条新的记录。
  {
  "acknowledged" : true,
  "matchedCount" : 0,
  "modifiedCount" : 0,
  "upsertedId" : 4
  }
{ "_id" : 4, "name" : "Pizza Rat's Pizzaria", "borough" : "Manhattan", "violations" : 7 }
   
db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d" }

2.6 增加/更新字段set和删除字段unset

不加条件,则更新第一条文档记录
db.blog.update({},{$set:{'num':''}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d" }

增加条件name为c的文档,增加一个字段
db.blog.update({'name':'c'},{$set:{'num':'2'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c", "num" : "2" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d" }

	
不加条件,更新所有文档增加一个字段,更新所有会覆盖掉之前的值
db.blog.update({},{$set:{'num':''}},{multi:1})
WriteResult({ "nMatched" : 4, "nUpserted" : 0, "nModified" : 3 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d", "num" : "" }


添加条件为name:c,时删除一个字段
db.blog.update({'name':'c'},{$unset:{'num':''}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d", "num" : "" }


不加条件,删除第一条记录。
db.blog.update({},{$unset:{'num':''}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b", "num" : "" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d", "num" : "" }


不加条件,删除字段,更新所有已存在的文档。
db.blog.update({},{$unset:{'num':''}},{multi:1})
WriteResult({ "nMatched" : 4, "nUpserted" : 0, "nModified" : 2 })

db.blog.find()
{ "_id" : ObjectId("5fc5a6a3e78f91ca2839cb16"), "name" : "a" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb17"), "name" : "b" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb18"), "name" : "c" }
{ "_id" : ObjectId("5fc5a6c3e78f91ca2839cb19"), "name" : "d" }


可以使用javascript代码添加和更新键
db.blog.insert(post)
WriteResult({ "nInserted" : 1 })

db.blog.find()
{ "_id" : ObjectId("5fc4ba63bad2853e0468a3c8"), "title" : "My Blog Post", "connect" : "Here is my blog post.", "date" : ISODate("2020-11-30T09:24:41.117Z") }

添加一个评论字段
db.blog.find().pretty()
{
"_id" : ObjectId("5fc5a524e78f91ca2839cb15"),
"title" : "My Blog Post",
"connect" : "Here is my blog post.",
"date" : ISODate("2020-12-01T02:06:19.189Z")
}

post.comments = []
[ ]
db.blog.update({'title':'My Blog Post'},post)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
db.blog.find().pretty()
{
"_id" : ObjectId("5fc5a524e78f91ca2839cb15"),
"title" : "My Blog Post",
"connect" : "Here is my blog post.",
"date" : ISODate("2020-12-01T02:06:19.189Z"),
"comments" : [ ]
}

2.7 $incr自增自减

使用$inc插入一条记录
db.games.update({"game" : "pinball", "user" : "joe"},{$inc:{'score':50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

因没有score这个键。在插入的时候自动创建这个键
db.games.find()
{ "_id" : ObjectId("5fd08a299ef0890ce971e161"), "game" : "pinball", "user" : "joe", "score" : 50 }

现在score增加10000
db.games.update({"game" : "pinball", "user" : "joe"},{$inc:{'score':10000}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

则score变成10050
db.games.find()
{ "_id" : ObjectId("5fd08a299ef0890ce971e161"), "game" : "pinball", "user" : "joe", "score" : 10050 }

现在score减去5000
db.games.update({"game" : "pinball", "user" : "joe"},{$inc:{'score':-5000}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
则score变为5050
db.games.find()
{ "_id" : ObjectId("5fd08a299ef0890ce971e161"), "game" : "pinball", "user" : "joe", "score" : 5050 }

2.8 数组的操作push,pull,pop,$(下标)

可以通过索引进行引用的列表,还可以作为数据集set来用

$push 
对数组末尾添加一个元素,如果数组不存在创建一个新数组

db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very good",
"email" : "123@163.com"
},
{
"content" : "very nice",
"email" : "abc@163.com"
},
123,
456,
789,
{
"content" : "very bad",
"eamil" : "456@163.com"
},
{
"content" : "very not nice",
"email" : "789@163.com"
}
]
}



不能用deleteOne来删除数组元素
db.game.deleteOne({'comments':123})
{ "acknowledged" : true, "deletedCount" : 0 }

使用$pull删除指定的数组元素。$pull是删除所有匹配条件的数组值
db.games.update({},{$pull:{'comments':123}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
db.games.update( {}, {$pull:{'comments':456}} )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
db.games.update( {}, {$pull:{'comments':789}} )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })


db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very good",
"email" : "123@163.com"
},
{
"content" : "very nice",
"email" : "abc@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
},
{
"content" : "very not nice",
"email" : "789@163.com"
}
]
}


使用$pop key:-1 来删除数组末尾的元素
db.games.update({},{$pop:{'comments':-1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
使用$pop key:1  来删除数组开头的元素
db.games.update({},{$pop:{'comments':1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })


db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very nice",
"email" : "abc@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
}
]
}


db.games.update( {"score" : 5050}, {$push:{'top10':{$each:[6,7,8,9,10,11,12,13,14,15,16,17,18]}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })


db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very nice",
"email" : "abc@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
}
],
"top10" : [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
]
}

使用$push时,如要限制元素个数使用$push和$slice来搭配使用。保证不会超过设定好的长度,slice必须是负整数。
虽然push了26-33 8个元素。但是只保留最后5个元素。可以再清理的时候使用$sort。添加数据就必须需要清理。
db.games.update( {"score" : 5050}, {$push:{'top10':{$each:[26,27,28,29,30,31,32,33],$slice:-5}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very nice",
"email" : "abc@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
}
],
"top10" : [
29,
30,
31,
32,
33
]
}


只能改数组的部分内容
通过下标对email进行修改。由abc修改为def 
db.games.update({'game':'pinball'},{$set:{'comments.0.email':'edf@163.com'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
 db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "very nice",
"email" : "edf@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
}
],
"top10" : [
3,
4,
5,
6,
7,
8,
9,
10,
11,
12
]
}

通过下标来修改值。可以用$符号来替代下标。因为有些时候只有查询才能确定下标。
使用$可以不写下标地址。 $只更新第一个匹配的结果
db.games.update({'comments.content':'very nice'},{$set:{'comments.$.content':'double very nice'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.games.find().pretty()
{
"_id" : ObjectId("5fd08a299ef0890ce971e161"),
"game" : "pinball",
"user" : "joe",
"score" : 5050,
"comments" : [
{
"content" : "double very nice",
"email" : "edf@163.com"
},
{
"content" : "very bad",
"eamil" : "456@163.com"
}
],
"top10" : [
3,
4,
5,
6,
7,
8,
9,
10,
11,
12
]
}

2.9 upsert 记录存在则更新否则插入一条新数据

db.email.update({'name':'upsert'},
... {$set:{'name':'upsert',email:'upsert@163.com'}}
... )
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })

db.email.find().pretty()
{
"_id" : ObjectId("5fd09fb79ef0890ce971e166"),
"name" : "abc",
"email" : "abc@163.com"
}
{
"_id" : ObjectId("5fd09fb79ef0890ce971e167"),
"name" : "def",
"email" : "def@163.com"
}
{
"_id" : ObjectId("5fd09fb79ef0890ce971e168"),
"name" : "ghi",
"email" : "ghi@163.com"
}

db.email.update({'name':'upsert'}, {$set:{'name':'upsert',email:'upsert@163.com'}},true )
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5fd718a37de2d14d3a30c553")
})

db.email.find().pretty()
{
"_id" : ObjectId("5fd09fb79ef0890ce971e166"),
"name" : "abc",
"email" : "abc@163.com"
}
{
"_id" : ObjectId("5fd09fb79ef0890ce971e167"),
"name" : "def",
"email" : "def@163.com"
}
{
"_id" : ObjectId("5fd09fb79ef0890ce971e168"),
"name" : "ghi",
"email" : "ghi@163.com"
}
{
"_id" : ObjectId("5fd718a37de2d14d3a30c553"),
"name" : "upsert",
"email" : "upsert@163.com"
}

3.DELETE 删除

3.1.db.collection.deleteOne() 删除符合条件的第一条文档

执行删除操作
db.inventory.deleteOne( { status: "D" } )              删除status为D的文档记录
返回结果:
{ "acknowledged" : true, "deletedCount" : 1 }		   提示删除了1条记录

3.2 db.collection.deleteMany() 删除所有符合条件的文档

执行删除操作
db.inventory.deleteMany({ status : "A" })             删除status为A的文档记录
返回结果:
{ "acknowledged" : true, "deletedCount" : 7 }		  提示删除7条记录		

3.3 也可以做删除操作的命令

db.collection.findOneAndDelete()  提供排序选项。该选项允许删除按指定顺序排序的第一个文档。
db.collection.findAndModify()     提供排序选项。该选项允许删除按指定顺序排序的第一个文档。
例:
db.ins.findAndModify({query:{'age':'9'},remove:true})

4.FIND 查询

  • 对于要查询的文档的值必须是常量

4.1 查询所有记录

类似于MySQL中的   select * from table
db.inventory.find()/db.inventory.find({})  两条命令相等
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44f"), "item" : "notebook", "qty" : 50, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "A" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }

4.2 条件查询

类似于MYSQL中 SELECT * FROM inventory WHERE status = "D" 
db.inventory.find( { status: "D" } ) 找到status等于D的文档。
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc451"), "item" : "planner", "qty" : 75, "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "status" : "D" }

4.3 IN查询

类似于MYSQL中SELECT * FROM inventory WHERE status in ("A", "D") 虽然可以使用or来做操作。但是官方更推荐使用in来查询。

db.inventory.find({ status: { $in: [ "A", "D" ]}})  搜索status等于A或D的文档。
db.inventory.find( { status: { $in: [ "A", "D" ] } } )
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44f"), "item" : "notebook", "qty" : 50, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "A" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc450"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }

4.4 AND查询

类似于MYSQL中 select * from inventory where status="A" and qty<30

and操作。找到status等于A且qty小于30的文档。
db.inventory.find({status:"A",qty:{$lt:30}})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }

4.5 OR查询

类似于MYSQL中SELECT * FROM inventory WHERE status = "A" OR qty < 30

查询status等于A 或 qty> 30的记录
db.inventory.find({$or:[{status:"A"},{qty:{$lt:30}}]})
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }
{ "_id" : ObjectId("5c85fcd906bbda89cc0dc44f"), "item" : "notebook", "qty" : 50, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "A" }

4.6 排序/美化/限制输出结果/跳过结果输出

Sort排序/Pretty美化
db.inventory.find().sort({name:1}).pretty() 对name字段进行排序,并且美化输出结果。
db.ins.find().sort({name:1}).pretty()
{
"_id" : ObjectId("5c85f93806bbda89cc0dc44b"),
"name" : "five doc",
"age" : "5",
"tag" : "five insert doc"
}
{
"_id" : ObjectId("5c85f85806bbda89cc0dc44a"),
"name" : "four doc",
"age" : "4",
"tag" : "four insert doc"
}


email有5个集合
db.email.count()

Limit限制返回结果    只返回2个结果
db.email.find().limit(2)
{ "_id" : ObjectId("5fd09fb79ef0890ce971e166"), "name" : "abc", "email" : "abc@163.com" }
{ "_id" : ObjectId("5fd09fb79ef0890ce971e167"), "name" : "def", "email" : "def@163.com" }

Skip跳过文档返回剩余文档    跳过前两个结果,返回余下的结果。
db.email.find().skip(2)
{ "_id" : ObjectId("5fd09fb79ef0890ce971e168"), "name" : "ghi", "email" : "ghi@163.com" }
{ "_id" : ObjectId("5fd718a37de2d14d3a30c553"), "name" : "up", "email": "upsert@163.com" }
{ "_id" : ObjectId("5fd71a2a2f1e32c5f863d32b"), "name" : "abc", "email" : "abc@164.com" }

4.7 查询数组文档(测试未通过在研究,跳过这一条)

查询数组文档
db.ins.insert({"name" : "11.sz", "age" : "11", "tags":["java","kpop","china"]})
db.ins.insert({name:'12',age:12,tags:[{'code':'java','music':'kpop'}]})

查询
db.ins.find()
[  {    _id: ObjectId("64dc11fea08ca24713ab4c56"),    name: '11.sz',    age: '11',    tags: [ 'java', 'kpop', 'china' ]
  },
  {
    _id: ObjectId("64dc11ffa08ca24713ab4c57"),
    name: '12',
    age: 12,
    tags: [ { code: 'java', music: 'kpop' } ]
  }
]


精确匹配数组文档,如果有一个字段是只有java才返回结果
db.ins.find({tags:["java"]}) 

精确匹配数组文档,有java,kpop,china才会返回结果。
db.ins.find({tags:["java","kpop","china"]}) 




db.ins.find({tags:"java"}) 模糊匹配,只要tags中带了java的就展示
 {
    _id: ObjectId("64dc11fea08ca24713ab4c56"),
    name: '11.sz',
    age: '11',
    tags: [ 'java', 'kpop', 'china' ]
  }
]

模糊匹配,只要tags中带了bike的就展示
db.ins.find({tags:"kpop"}) 模糊匹配,只要tags中带了bike的就展示

4.8 模糊查询

类似MySQL中的     select * from users where name like '%a%'
db.users.find({name:/.*a.*/}) 模糊匹配查询,带a字母的,无论a在前后
db.users.find({name:/^a.*/}) 模糊匹配查询,name以a开头的结果查询 
db.users.find({name:/.*a$/}) 模糊匹配查询,name以a结尾的结果查询

4.9 嵌套文档查询/投影(只返回特定字段)

文档嵌套查询
(用户评论,商品订单,买了一个东西,商品的名称价格数量)(例子)
{ "_id" : ObjectId("5b58b9544983f690c7ab9687"), "name" : "baby3", "age" : 18, "address" : { "country" : "china", "city" : "hangzhou", "district" : "xihu", "dd" : "zhongguancunroad 10" } }
{ "_id" : ObjectId("5b58b9784983f690c7ab9688"), "name" : "xiaowang", "age" : 19, "address" : { "country" : "china", "city" : "shanghai", "district" : "pudong", "dd" : "sjtu park 10" } }

查询时应该包含外围的字段和内部的字段,可以不按顺序来查询。也可以严格按照顺序来查询。
db.users.find({"address.country":'china'}) country是address文档中的字段,注意用.来引用
db.users.find({"address.city":'hangzhou'})
db.users.find({age:18,"address.city":'hangzhou'}) 
db.users.find({age:{$lt:18},"address.city":'hangzhou'}) 可以使用条件来限制比如年龄小于18岁的
db.orders.find({'item.0.count':{$lt:2}})   第0个元素满足,按照第一个元素范围是大于2的。
db.orders.find({"item.count":{$gt:0,$lte:100}}) 多条件and查询
	
投影(映射)返回特定的字段
db.users.find({age:18},{name:1,age:1}) 查询年龄是18岁的。但只返回name字段和age字段
db.users.find({age:{$gt:29}},{name:1,age:1}) 查询年龄大于29的。但是只返回name和age字段
db.users.find({age:{$gt:29}},{name:0}) 查询年龄大于29的。不返回name字段,剩下都返回

4.10 去重/聚合

distinct去重
db.users.distinct("name") 去掉重复的名字,显示不重复的名字
db.orders.distinct("items.count") 去掉重复的计数,显示不重复的计数
db.users.distinct("name ",{age:18}) 查询年龄等于18的,并对name字段进行去重
db.orders.distinct("item.count ",{age:18}) 查询年龄18岁的。并对items.count计数字段去重
db.users.distinct("city")
db.users.distinct("address.city")
等价写法
db.runCommand({distinct:"users",key:"name"})
为了性能,尽量使用索引,支持优先查询节点。
   	
group by聚合统计分析
有三种,聚合函数(早期功能),聚合管道,mapreduce(应对大数据分析)。
简单的使用group方法。3.4过期,建议使用新的聚合,db.collections.aggregate()+$group或者db.collections.mapreduce

分组统计不同年龄段的用户
db.users.group(
{
key:{age:1},
cond:{age:{$gt:16}},
reduce:function(curr,result){
result.total +=1;
},
initial:{total:0}
}
)

分组统计不同用户的订单总额
db.orders.grop(
{
key:{name:1},
cond:{},
reduce:function(curr.result){
result.total += curr.price;
},
initial:{total:0}
}
)

分组统计不同用下的订单数
db.orders.group( 
{ 
key:{name:1}, 
cond:{}, 
reduce:function(curr,result){ 
result.total +=1; }, 
initial:{total:0} 
} 
)

分组统计不同用户消费金额
db.orders.group( 
{ 
key:{name:1}, 
cond:{}, 
reduce:function(curr,result){ 
result.total =curr.price 
}, 
initial:{total:0} 
} 
)

4.11 null值的查询

a集合包含一个null值
db.a.find()
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab90"), "y" : null }
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab91"), "y" : 1 }
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab92"), "y" : 2 }

通过条件查询可以查询到这个null值
db.a.find({'y':null})
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab90"), "y" : null }

对于不存在的z查询的时候,会返回所有的值
db.a.find({'z':null})
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab90"), "y" : null }
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab91"), "y" : 1 }
{ "_id" : ObjectId("5fd9b25c1d2a682a33b3ab92"), "y" : 2 }

检查z是否为null值,还要通过exists判断键是否存在。可以避免上边的问题。
db.a.find({'z':{$in:[null],$exists:true}})

4.12 FIND补充

Find操作符作用
查询操作符
比较查询运算符
$eq匹配等于指定值的值。
$gt匹配大于指定值的值。
$gte匹配大于或等于指定值的值
$in匹配数组中指定的任何值。
$lt匹配小于指定值的值。
$lte匹配小于或等于指定值的值。
$ne匹配所有不等于指定值的值。
$nin不匹配数组中指定的任何值。
逻辑查询运算符
$and使用逻辑连接查询子句AND将返回与两个子句的条件匹配的所有文档。
$not反转查询表达式的效果并返回与查询表达式不匹配的文档。
$nor使用逻辑连接查询子句NOR将返回所有无法匹配两个子句的文档。
$or使用逻辑连接查询子句OR将返回与任一子句的条件匹配的所有文档。
元素查询运算符
$exists匹配具有指定字段的文档。
$type如果字段是指定类型,则选择文档。
求值查询运算符
$expr允许在查询语言中使用聚合表达式。
$jsonSchema根据给定的JSON模式验证文档。
$mod对字段的值执行模运算,并选择具有指定结果的文档。
$regex选择值与指定正则表达式匹配的文档。
$text执行文本搜索
$where匹配满足JavaScript表达式的文档。
地理空间查询运算符
$geoIntersects选择与GeoJSON几何体相交的几何。该2dsphere索引支持
$geoWithin选择边界GeoJSON几何体内的几何。该2dsphere和2D索引支持。
$near返回点附近的地理空间对象。需要地理空间索引。
$nearSphere返回球体上某点附近的地理空间对象。需要地理空间索引。
数组查询运算符
$all匹配包含查询中指定的所有元素的数组
$elemMatch如果数组字段中的元素与所有指定$elemMatch条件匹配,则选择文档。
$size如果数组字段是指定大小,则选择文档。
按位查询运算符
$bitsAllClear匹配数值或二进制值,其中一组位位置都具有值0。
$bitsAllSet匹配数值或二进制值,其中一组位位置都具有值1。
$bitsAnyClear匹配数值或二进制值,其中来自一组位位置的任何位的值都为0。
$bitsAnySet匹配数值或二进制值,其中来自一组位位置的任何位的值都为1。
投影查询运算符
$投影数组中与查询条件匹配的第一个元素。
$elemMatch投影数组中与指定$elemMatch条件匹配的第一个元素。
$meta投影在$text操作期间分配的文档分数。
$slice限制从数组投射的元素数量。支持跳过和限制切片。