MongoDB基本操作之CRUD

原文作者: xingguang
原文链接:https://www.tiance.club/post/1234652124.html

创建文档

命令有三种:

创建单个文档:db.collection.insertOne()
创建单个或多个文档:db.collection.insert()
创建多个文档:db.collection.insertMany()

insertOne

示例:

db.goods.insertOne({
	name:"哈士奇饼干",
	price:33,
})

返回结果:

{
    "acknowledged": true,
    "insertedId": ObjectId("5e9c52e32a170000ea003e5a") //5e9c544c2a170000ea003e5b为本次插入数据的主键id
}

插入复合主键

db.goods.insertOne({
    _id:{id:123,type:‘shop‘},
	name:"这个是复合组件",
	price:20.58,
})

insertMany

示例:

db.goods.insertMany([
	{name:"哈士奇饼干1",price:33,},
	{name:"神奇宝贝一只1",stock:100,price:20.58,}
])

返回结果:

{
    "acknowledged": true,
    "insertedIds": [
        ObjectId("5e9c56b72a170000ea003e5d"),
        ObjectId("5e9c56b72a170000ea003e5e")
    ]
}
原文作者: xingguang
原文链接:[https://www.tiance.club/post/1234652124.html](https://www.tiance.club/post/1234652124.html)

insert

示例:

db.goods.insert([
	{name:"哈士奇饼干1",price:33,},
	{name:"神奇宝贝一只1",stock:100,price:20.58,}
])

返回结果:

BulkWriteResult({
	"nRemoved" : 0,
	"nInserted" : 2, //插入成功的数量
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"writeErrors" : [ ]
})

查询文档

读取全部文档

既不筛选,也不投射

db.collection.find();

示例:

db.goods.find();

返回结果:

// 1
{
    "_id": ObjectId("5e9c48b42a170000ea003e45"),
    "name": "纸巾一包",
    "price": 100
}

// 2
{
    "_id": ObjectId("5e9c48eb2a170000ea003e48"),
    "name": "奶茶一杯",
    "price": 20.58
}

// 3
{
    "_id": ObjectId("5e9c56b72a170000ea003e5d"),
    "name": "哈士奇饼干1",
    "price": 33
}

匹配查询

示例:

//查询名字为"纸巾一包"并且价格为100元的数据
db.goods.find({name:"纸巾一包",price:100})

返回结果

{
    "_id": ObjectId("5e9c48b42a170000ea003e45"),
    "name": "纸巾一包",
    "price": 100
}

复合主键查询

db.goods.find({"_id.type":"shop"})

操作符

比较操作符

{:{$:}}
$eq 匹配字段值相等的文档 (可以用于string和int类型) =
$ne 匹配字段值不等的文档 !=
$gt 匹配字段值大于查询值的文档 >
$gte 匹配字段值大于或等于查询值的文档 >=
$lt 匹配字段值小于查询值的文档 <
$lte 匹配字段值小于或等于查询值的文档 <=
$in 匹配字段值与任意查询值相等的文档 "in"
$nin 匹配字段值与任意查询值不相等的文档 "not in"

//匹配查询
db.goods.find({name:{$eq:"纸巾一包"}})
//in查询
db.goods.find({"name":{$in:["纸巾一包","奶茶一杯"]}})
//读取价格大于32元且小于101元的商品
db.goods.find({price:{$gt:32,$lt:101}})
//复合组件查询
db.goods.find({"_id.type":{$eq:"shop"}})
db.goods.find({"_id.type":{$in:["shop"]}})
逻辑操作符

$not 匹配筛选条件不成立的文档
$and 匹配多个筛选条件全部成立的文档
$or 匹配至少一个筛选条件成立的文档
$nor 匹配多个筛选条件全部不成立的文档
逻辑运算符示例:

//查询价格不小于32元的商品
db.goods.find({price:{$not:{$lt:32}}})
//相当于下面的取反
db.goods.find({price:{$lt:32}})
//获取价格为100,并且名称为"纸巾一包"的商品
db.goods.find({
	$and:[
		{price:{$eq:100}},
		{name:"纸巾一包"}
	]
})
//可以简写如下
db.goods.find({price:{$eq:100},name:"纸巾一包"})
//获取价格不是100,并且名称不为"纸巾一包"的商品
db.goods.find({
	$nor:[
		{price:{$eq:100}},
		{name:"纸巾一包"}
	]
})
注意:nor也会筛选出并不包含查询字段的文档!!比如会把没有price和name字段的文档也查出来!
字段操作符
$exists 匹配包含查询字段的文档  
$type 匹配字段符合查询值的文档

$type对应的类型和BSON类型序号

Double	1	 
String	2	 
Object	3	 
Array	4	 
Binary data	5	 
Undefined	6	已废弃。
Object id	7	 
Boolean	8	 
Date	9	 
Null	10	 
Regular Expression	11	 
JavaScript	13	 
Symbol	14	 
JavaScript (with scope)	15	 
32-bit integer	16	 
Timestamp	17	 
64-bit integer	18	 
Min key	255	Query with -1.
Max key	127

示例

//查询复合主键中存在type字段的数据
db.goods.find({"_id.type":{$exists:true}})
//查询存在name字段的数据
db.goods.find({name:{$exists:true}})
//查询类型为普通主键和复合主键的数据
db.goods.find({_id:{$type:["objectId","object"]}})
//查询类型为string的数据
db.goods.find({name:{$type:["string"]}})
数组操作符
$all 匹配数组字段中包含所有查询值的文档
$elemMatch 匹配数组字段中至少存在一个值满足筛选条件的文档

示例

先插入数据
db.goods.insert(
	[
		{
		    name:"皮卡丘一只",
			price:100,
			contact:["111111","Alabama","US"]
		},
		{
		    name:"小火龙一只",
			price:120,
			contact:[["222222","333333"],"Beijing","China"]
		}
	]
)

原文作者: xingguang
原文链接:https://www.tiance.club/post/1234652124.html

//查询contact字段中同时包含"China"和"Beijing"字段的文档
db.goods.find({contact:{$all:["China","Beijing"]}})
//查询联系方式中包含"222222","333333"的文档,注意,这里的数组如果只有"222222"是查询不到的,这里是数组全等的关系
db.goods.find({contact:{$all:[["222222","333333"]]}})
//查询电话号码范围在大于111110和小于222222之间的数据
db.goods.find({contact:{$elemMatch:{$gt:"111110",$lt:"222222"}}})
//查询电话号码范围在"大于111110和小于222222之间"并且"大于211111和小于444444之间"的数据
db.goods.find({
	contact:{$all:[
		{$elemMatch:{$gt:"111111",$lt:"222222"}},
		{$elemMatch:{$gt:"211111",$lt:"444444"}}
	]}
})
运算操作符
{<field>:{:/pattern/,:‘<options>‘}}
{<field>:{:/pattern/<options>}}
$regex  
在和$in操作符一起使用时,只能使用/pattern/<options>
//读取name字段以"皮"或"j"开头的文档数据
db.goods.find({name:{$in:[/^皮/,/^j/]}})

//读取name字段包含LIE(不区分大小写)的文档数据
db.goods.find({name:{$regex:/LIE/,$options:‘i‘}})

游标

游历完游标中所有文档之后,或者在10分钟之后,游标便会自动关闭
可以使用noCursorTimeout()函数来保持游标一直有效

var myCursor=db.goods.find().noCursorTimeout()

在这之后,在不遍历游标的情况下,你需要主动关闭游标

myCursor.close()

原文作者: xingguang
原文链接:https://www.tiance.club/post/1234652124.html

游标函数
cursor.hasNext() //当还有没遍历完的游标文档时,返回true
cursor.next()  //获取下一次遍历的游标文档
cursor.forEach(<function>) //遍历游标中所有指向的文档
cursor.limit(<number>)  //返回指定条数
cursor.skip(<offest>) //跳过文档中指定数量的文档(传入1表示跳过第一篇文档)
cursor.count(<applySkipLimit>) //默认情况下,<applySkipLimit>为false,即cursor.count()不会考虑cursor.skip()和cursor.limit()的效果
cursor.sort(<document>)  //这里的<document>定义了排序的要求(1从小到大排序,-1从大到小排序)
var myCursor=db.goods.find();
while(myCursor.hasNext()){
	printjson(myCursor.next());
}


var myCursor=db.goods.find();
myCursor.forEach(printjson)
db.goods.find().limit(1)
db.goods.find().skip(1)

db.goods.find().limit(1).count() //返回所有文档总数
db.goods.find().limit(1).count(true) //返回一篇文档
//price字段从大到小排序,并且name字段由小到大排序 (相当于mysql中同时两个排序条件的规则)
db.goods.find().sort({price:-1,name:1})

注意事项
cursor.skip(),cursor.limit(),cursor.count()
优先级:count()->skip()->limit()

cursor.skip()在cursor.limit()之前执行
db.goods.find().limit(5).skip(3)
结果返回的是5篇文章,从第4篇到第9篇文章
cursor.count()在cursor.skip()和cursor.limit()之前执行
db.goods.find().limit(5).skip(3).sort({price:-1})

文档投影

db.goods.find(<query>,<projection>)
不使用投影时,db.goods.find()返回符合筛选条件的完整文档
使用投影可以只返回指定的字段
{field:inclusion}
1表示返回部分字段,0表示不返回字段,(1和0不可组合使用,_id字段除外)
//只返回name字段
db.goods.find({},{name:1,_id:0})
//返回除name之外的字段
db.goods.find({},{name:0})
//$slide:2,表示返回前2条,-2表示返回倒数2条,[1,2]表示返回第二条到第三条
db.goods.find({},{name:1,content:{$slide:[1,2]}})

$elemMatch和$操作符可以返回数组字段中满足筛选条件的第一个元素

//返回content数组字段中第一个排序大于"Alabama"的数据,(没content字段的文档也会被返回)
db.goods.find({},{name:1,content:{$elemMatch:{$gt:"Alabama"}}})

//返回content数组字段中第一个排序大于"Alabama"的数据
db.goods.find({content:{$gt:"Alabama"}},{name:1,"content.$":1,})

更新操作

注意:
1、
db.goods.update(where查询条件,更新的值,其它条件)
db.goods.update({"uid":3},{$rename:{"name":"alias"}},{multi:true})
2、文档更新操作只会更新一篇文档,即使条件符合多篇文档,也只会更新一篇,如果想要更新所有符合条件的文档,需要添加第三个参数{multi:true}

文档更新操作符

$set 更新或新增字段
$unset 删除字段
$rename 重命名字段 {$rename:{<field1>:<newName1>,<field2>:<newName2>}}
$inc 加减字段值  (字段不存在时,会默认创建且值为加减的值)
$mul 相乘字段值 (字段不存在时,会默认创建且值为0 )
$min 比较减少字段值 (保留最小的值)(字段不存在会自动创建且值为指定的值)(类型不一致按BSON数据类型排序规则比较)
$max 比较增大字段值 (保留最大的值)(字段不存在会自动创建且值为指定的值)(类型不一致按BSON数据类型排序规则比较)
//($rename)重命名写法
db.goods.update({"uid":3},{$rename:{"name":"alias"}})
//($rename)将数组字段content中的name字段迁移到最外面的name字段
db.goods.update({"uid":3},{$rename:{"content.name":"name"}})
//($rename)将最外面的name字段迁移到数组字段content中的name字段
db.goods.update({"uid":3},{$rename:{"name":"content.name"}})
//($inc)将条件uid=3的文档,price字段加一
db.goods.update({"uid":3},{$inc:{"price":1}})
//($min)源字段大于50时,修改成50
db.goods.update({"uid":3},{$min:{"price":50}}) (源price值为30时,不变,保留30)
BSON数据类型排序规则
最小
	Null
	Numbers(ints,longs,doubles,decimals)
    Symbol,String
	Object
	Array
	BinData
	ObjectId
	Boolean
	Date
最大
	Regular Expression

数组更新操作符

$addToSet 向数组中增添元素
$pop 从数组中移除元素
$pull 从数组中移除指定元素
$pullAll 从数组中有选择性地移除元素
$push 向数组中增添元素
//($addToSet)将content数组字段添加"nihao","wohao"两个值
db.goods.update({"uid":3},{$addToSet:{"content":{$each:["nihao","wohao"]}}})
//$pull删除content数组中包含"皮"字的字段
db.goods.update({"uid":3},{$pull:{"content":{$regex:/皮/}}})
{$pullAll:{<field>:[<vaule1>,<vaule2>]}}
相当于
{$pull:{<field>:{$in:[<vaule1>,<vaule2>]}}}

更新操作符

$ 第一个符合条件的占位符
$[] 数组中的所有元素

更新数组中的特定元素
$是数组中第一个符合筛选条件的数组元素的占位符,搭配更新操作符使用,可以对满足筛选条件的数组元素进行更新

db.goods.update({<array>:<query selector>},<update operator>:{"<array>.$",vaule})

$[]指代数组字段中的所有元素,搭配更新操作符使用,可以对数组中的所有元素进行更新

db.goods.update({<array>:<query selector>},<update operator>:{"<array>.$[]",vaule})
//源数据
{
    "_id": ObjectId("5e9f08904757000020000235"),
    "content": [
        "nihao",
        "我很好"
    ],
    "uid": 3,
    "name": "nihao",
    "num": 1,
    "num1": 0
}
//将content数组中值为"nihao"的替换成"updated"
db.goods.update({
    uid:3,
	content:"nihao"
}, {
    $set: {
        "content.$":"updated"
    }
})
将content数组中所有字段替换成"updated"
db.goods.update({
    uid:3
}, {
    $set: {
        "content.$[]":"updated"
    }
})

更新文档选项

{multi:}
更新多个文档
到目前为止,我们在update命令中使用的筛选条件只对应一篇文档
在默认情况下,即使筛选条件对应了多篇文档,update命令仍然只会更新一篇文档

将所有name值为"nihao"的文档num值改成10
db.goods.update({
    name:"nihao"
}, {$set: {"num":10}},{multi:true})

原子性

在MongoDB中,更新单个的文档操作是原子性的。默认情况下,如果一个update()更新多个文档,那么对每个文档的更新是原子性的,但是对整个update而言则不是原子性的。有可能存在前一个文档更新成功,后面的文档更新失败的情况。由于单个文档的更新是原子性的,如果两个更新同时发生,就会出现阻塞,先到的先执行,所以文档最终结果由靠后的操作决定。
**简单的说就是对同一篇文档进行更新,文档最终结果以最后的更新操作为结果**

删除命令

db.collection.remove() 删除文档
db.collection.drop() 删除集合

注:
1、删除文档默认是删除所有符合条件的文档,和update操作不一样,如果需要指定只删除一篇文档,加上第二个参数({justOne:true})

删除文档

db.<collection>.remove(<query>,<options>)
<options>声明了一些删除操作的参数

db.goods.remove()
//删除name值为"nihao"的所有文档
db.goods.remove({name:"nihao"})
//删除name值为"nihao"的一篇文档({justOne:true})
db.goods.remove({name:"nihao"},{justOne:true})
//删除集合内的所有文档
db.goods.remove({})

删除集合

db.<collection>.drop(<writeConcern>,<document>)
db.goods.drop()

这里的writeConcern文档定义了本次集合删除操作的安全写级别、
drop命令可以删除整个集合,包括集合中的所有文档,以及集合的索引

原文作者: xingguang
原文链接:https://www.tiance.club/post/1234652124.html