MongoDB CRUD操作
MongoDB CRUD操作即创建(create)、读取(read)、更新(update)、删除(delete) documents。本文我们介绍一下这些操作,在此做个记录,以便后续查阅。
1. CRUD操作
1.1 Create操作
创建(create)或插入(insert)操作可以添加新documents到一个collection。假如collection当前不存在,那么插入操作会自动的创建该collection。
MongoDB提供了如下的方法来插入documents到collection:
-
db.collection.insertOne()New in version 3.2
-
db.collection.insertMany()New in version 3.2
在MongoDB中,插入操作的目标(target)只能是一个collection。
MongoDB针对单个
(single)document的写操作均为原子性(atomic)的。
更多示例,请参看Insert Documents。
1.2 读操作
读(Read)操作可以从collection中获取documents,比如从collection中查询documents。MongoDB提供如下的方法来从collection中读取documents:
可以指定query filters or criteria来标识需要返回哪些documents:
更多示例,请参看:
- Query Documents
- Query on Embedded/Nested Documents
- Query an Array
- Query an Array of Embedded Documents
1.3 更新操作
更新(update)操作用于修改collection中已存在的documents。MongoDB提供了如下的方法来更新collection中documents:
- db.collection.updateOne() New in version 3.2
- db.collection.updateMany() New in version 3.2
- db.collection.replaceOne() New in version 3.2
MongoDB中,更新操作的目标(target)只能是一个collection。MongoDB针对单个
(single)document的所有写操作均为原子性(atomic)的。
在执行更新操作时可以指定criterial, filters来更新特定的documents。这些filters与读操作的filters具有完全一样的语法。
更多示例,请参看Update Documents
1.4 删除操作
删除(delete)操作可以从collection中移除documents。MongoDB提供了如下的方法来从一个collection中删除documents:
- db.collection.deleteOne() New in version 3.2
- db.collection.deleteMany() New in version 3.2
MongoDB中,删除操作的目标(target)只能是一个collection。MongoDB针对单个
(single)document的所有写操作均为原子性(atomic)的。
更多示例,请参看Delete Documents
1.5 Bulk Write
MongoDB提供了批量写操作。更多详细细节,请参看Bulk Write Operations
2. Insert Documents
Note: 假如collection当前不存在,insert操作会创建对应的collection
Insert a Single Document
db.collection.insertOne()可以将单个document插入到collection。
如下的示例插入一个新的document到inventory
这个collection中。假如document未指定_id
字段的话,MongoDB会添加一个_id
字段,并赋予一个ObjectId值。参看Insert Behavior。
insertOne()方法会返回新插入的document的_id
字段值。要查看返回的document示例,请参看 db.collection.insertOne() reference
如果要查询刚刚插入的document,执行query the collection
Insert Multiple Documents
New in version 3.2.
db.collection.insertMany()可以插入多个document到collection中。可以传递一个document数组作为参数。
如下的示例插入3个documents到inventory
集合中。假如document并未指定_id
字段的话,那么MongoDB会帮助为每个document生成一个_id
字段,值为ObjectId类型。参看Insert Behavior。
insertMany()会返回一个document,里面包含新插入
的documents的_id
。参看reference以了解相关示例。
要查询所插入的documents的话,执行query the collection。
Insert Behavior
1) Collection Creation
假如对应的collection不存在的话,insert操作会创建对应的collection。
2) _id字段
在MongoDB中,collection中的每一个document都需要一个唯一的_id
字段来作为primary key。假如所插入的document未指定_id
字段的话,MongoDB driver会自动为_id
字段生成一个ObjectId。
当执行update操作时,如果upsert: true被设置的话,当执行的结果是插入document的话,也同样会生成_id
字段。
3) Atomicity
在MongoDB中,对于单个
document来说所有的写操作都是原子性。更多关于MongoDB及原子操作,请参看Atomicity and Transactions。
4) Write Acknowledgement
对于数据库的写操作,我们可以指定MongoDB的ack响应级别。参看Write Concern
2.1 Insert Methods
MongoDB提供了如下的方法来向collection中插入documents:
-
db.collection.insertOne() 插入一个document到collection
-
db.collection.insertMany() 插入多个document到collection
2.2.1 Additional Methods for Inserts
如下的方法也可以插入documents到collection:
- db.collection.updateOne() when used with the upsert: true option.
- db.collection.updateMany() when used with the upsert: true option.
- db.collection.findAndModify() when used with the upsert: true option.
- db.collection.findOneAndUpdate() when used with the upsert: true option.
- db.collection.findOneAndReplace() when used with the upsert: true option.
- db.collection.bulkWrite().
3. Query Documents
本节我们提供一些使用db.collection.find()方法的示例来演示查询操作。例子使用的collection为inventory
。首先我们向集合中插入一些数据,执行如下:
Select All Documents in a Collection
要查询collection中所有的documents,可以向find()方法传递一个empty document作为查询过滤器。查询过滤器(query filter)决定了查询准则:
上面的操作对应于如下SQL语句:
SELECT * FROM inventory
更多关于find()方法的语法信息,请参看find()
Specify Equality Condition
要指定相等条件
(equality conditions),在query filter document中使用<field>:<value>
:
下面的例子从inventory
这个collection中查询status
等于D
的记录:
该操作对应于如下的SQL语句:
SELECT * FROM inventory WHERE status = "D"
Specify Conditions Using Query Operators
一个query filter document可以通过如下形式来使用query operators:
下面的列子获取inventory
这个collection中所有status
等于"A"
或D
的记录:
该操作对应于如下SQL语句:
参看Query and Projection Operators以了解MongoDB query operators的完整列表。
Specify AND
Conditionsicons
一个复合查询可以指定collection documents中的多个字段作为查询条件。我们可以使用AND
来连接所有的查询条件。
如下的示例查询inventory
这个collection中所有status
为"A"
且qty
小于等于30的记录:
上述语句等价于如下的SQL语句:
更多比较操作符,请参看comparison operators。
Specify OR Conditions
在进行一个符合查询时,我们可以使用$or操作符来多个查询条件,只要collection中的documents满足其中一个条件,即匹配成功。
如下的示例查询inventory
这个collection中status
为"A"
或qty
小于等于30的数据记录:
上面的查询语句等价于如下SQL语句:
Note: Queries which use comparison operators are subject to Type Bracketing.
Specify AND as well as OR Conditions
如下的例子中,查询inventroy
这个collection中status
为"A"
,且qty
小于等于30或item
以字符p
开头的数据记录:
上面的语句对应于如下SQL查询语句:
Note: MongoDB支持正则表达式$regex查询,查询某字段匹配某个pattern
Additional Query Tutorials
对于其他的查询示例,请参看:
- Query on Embedded/Nested Documents
- Query an Array
- Query an Array of Embedded Documents
- Project Fields to Return from Query
- Query for Null or Missing Fields
Behavior
1) Cursor
db.collection.find()会为所匹配的documents返回一个cursor。
2) Read Isolation
New in version 3.2
如果从replica set或replica set shards中执行查询的话,允许客户端选择读取的隔离级别。更详细信息,请参看Read Concern。
3.1 Query on Embedded/Nested Documents
如下提供一个示例,在mongosh中使用db.collection.find()方法查询内嵌documents。我们使用inventory
这个collection。首先向其中填充如下数据:
Match an Embedded/Nested Document
要查询内嵌document中某个字段,使用query filter document { <field>:<value>}
,其中<value>
为所要匹配的document.
下面的例子查询size
字段等于{ h: 14, w: 21, uom: "cm" }
的document:
对一个内嵌document做Equality
匹配的话,要求严格
(exact)的完全匹配,包括其中的字段顺序。例如,如下的查询将匹配不上inventory
这个collection中的任何document:
Query on Nested Field
如果要使用内嵌document中某个字段作为查询条件来查询的话,使用dot notation("field.nestedField"
)。
Note: 当使用dot notation来执行查询的话,查询字段必须在双引号内
1) Specify Equality Match on a Nested Field
下面的例子查询size
中的内嵌字段uom
等于in
的所有document:
2) Specify Match using Query Operator
一个query filter document可以使用query operators来指定查询条件,形式如下:
下面的示例使用less than operator ($lt)在size
的内嵌字段h
上做查询:
3) Specify AND Condition
如下查询内嵌字段h
小于15,内嵌字段uom
等于in
,且status
等于D
的documents:
Additional Query Tutorials
其他查询示例,请参看:
3.2 Query an Array
本节我们提供一些示例,使用db.collection.find()方法在数组字段上做查询。例子使用inventory
这个collection。下面我们先向该collection填充一些数据:
Match an Array
要在一个数组上指定equality condition,使用query document { <field>: <value>}
,其中<value>
与数组严格匹配,包含数组顺序也要匹配。
如下的例子查询的字段tags
的值为数组,且按顺序值为red
和blank
的document:
另外,假如你仅仅只想查询一个数组中含有red
及blank
元素(不关心顺序,也不关心是否有其他元素),请使用$all operator。
Query an Array for an Element
如果要查询数组中至少
包含某一指定值,使用filter {<field>: <value>}
,其中<value>
为数组元素的值。
如下的例子查询tags
字段至少含有red
元素的documents:
如果要在数组字段的elements上指定查询条件的话,可以在query filter document上使用query operators:
例如,下面的操作查询dim_cm
数组中至少包含一个元素,该元素的值大于25:
Specify Multiple Conditions for Array Elements
当需要在数组元素上指定复合条件的话,你可以为单个
数组元素指定查询条件,也可以为多个
数组元素指定查询条件.
1) Query an Array with Compound Filter Conditions on the Array Elements
下面的例子查询dim_cm
数组中元素满足匹配条件的documents。例如,数组中有一个元素大于15且有另一个元素小于20, 或者某一个元素同时满足这两个条件的documents:
2) Query for an Array Element that Meets Multiple Criteria
使用$elemMatch操作符来为数组中的元素指定多个准则(criteria),要求数组中至少有一个元素匹配所有准则。
如下的示例查询dim_cm
数组中至少有一个元素同时满足:大于($gt)22,且小于($lt)30
3) Query for an Element by the Array Index Position
使用dot notation,你可以为某一特定index上的数组元素指定查询条件。数组下表从0开始索引。
Note: 当使用dot notation执行查询时,所查询的field(包括内嵌field)必须在双引号中
下面的示例查询dim_cm
数组中第二个元素大于25的所有documents:
4) Query an Array by Array Length
使用$size操作符来查询一个数组中数组元素的个数。例如,下面查询tags
数组有3个元素的documents:
Additional Query Tutorials
更多查询示例,请参看:
3.3 Query an Array of Embedded Documents
本节提供一些示例,使用db.collection.find()方法查询数组元素为内嵌
(nested) documents的记录。例子基于inventory
这个collection,这里我们首先向该collection填充一些数据:
Query for a Document Nested in an Array
下面的例子查询instock
数组中匹配指定条件的documents:
对整个内嵌(embeded/nested)document的Equality匹配要求对指定的document严格匹配,包括字段的顺序。例如,如下的查询将匹配不上inventory
这个collection中的任何document:
Specify a Query Condition on a Field in an Array of Documents
1) Specify a Query Condition on a Field Embedded in an Array of Documents
假如你不知道某一document在内嵌数组中的索引位置,那么可以使用.
(dot)将将数组字段的名称(array-field-name)与内嵌document字段名称(nested-document-field-name)连接起来。
如下的示例查询instock
数组至少有一个内嵌元素含有qty
字段,且该字段的值小于等于20:
2) Use the Array Index to Query for a Field in the Embedded Document
使用dot notation,你可以为数组中某个索引(position)位置上的内嵌document字段指定查询条件。数组的索引从0开始。
Note: 当使用dot notation时,字段(field)与索引(index)必须在双引号中
下面的例子查询instock
数组中第一个document元素含有内嵌qtr
字段,并且该字段的值小于等于20:
Specify Multiple Conditions for Array of Documents
当需要对一个数组内嵌document的多个field指定查询条件时,你可以为内嵌的单个
document指定多个匹配条件,也可以为多个
document指定多个匹配条件。
1) A Single Nested Document Meets Multiple Query Conditions on Nested Fields
使用$elemMatch operator为数组中的内嵌document指定多个准则
(criteria),要求数组中至少有一个内嵌document匹配所有准则。
下面的示例查询instock
数组中至少有一个内嵌document同时含有字段qty
等于5,且含有字段warehouse
等于A
:
2) Combination of Elements Satisfies the Criteria
假如对于数组字段(field)执行复合条件查询时不使用
$elemMatch的话,则只要数组中的内嵌document的任何组合(可以多个内嵌documents组合在一起)满足查询条件即匹配成功。
例如,下面查询instock
数组中任何内嵌document含有qty
字段大于10,以及数组中任何内嵌document(没必要是同一个内嵌document)含有qty
字段小于等于20:
下面的例子查询instock
数组中至少一个内嵌document含有字段qty
等于5,且至少一个内嵌document(没必要是同一内嵌document)含有字段warehouse
等于A
:
Additional Query Tutorials
更多查询示例,请参看:
3.4 Project Fields to Return from Query
Note: projection这里可以翻译为“字段筛选”
默认情况下,在MongoDB中执行查询会返回所匹配的documents中的所有字段。为了限制返回给应用程序的数据量,我们可以使用一个projection document来指定(specify)或限制(restrict)返回的字段(field)。
本节提供一些查询示例,使用db.collection.find()方法执行查询,并返回指定的字段。例子基于inventory
这个collection,这里我们首先向该collection填充一些数据:
Return All Fields in Matching Documents
假如不指定一个projection document的话,则db.collection.find()会返回匹配字段的所有元素。
下面的示例返回inventory
这个collection中status
等于"A"
的document的所有字段:
上面的查询语句等价于如下SQL语句:
SELECT * from inventory WHERE status = "A"
Return the Specified Fields and the _id
Field Only
可以通过projection显式的指定返回哪些字段,方法是将返回的<field>
设置为1。如下的操作返回匹配查询条件的所有documents。在返回的结果集中,只包含item
及status
字段,以及默认情况下的_id
字段。
上述查询语句对应于如下SQL语句:
SELECT _id, item, status from inventory WHERE status = "A"
Suppress _id
Field
我们可以在projection中将_id
字段设置为0,从而返回结果中不含有_id
字段:
例子中查询语句对应于如下SQL语句:
SELECT item, status from inventory WHERE status = "A"
Note: 除了
_id
字段外,你不能在projection document中同时使用inclusion与exclusion
Return All But the Excluded Fields
我们可以使用projection来排除返回某些字段。下面的示例会返回除status
及instock
字段外的所有其他字段:
Note: 除了
_id
字段外,你不能在projection document中同时使用inclusion与exclusion
Return Specific Fields in Embedded Documents
我们可以返回内嵌document的指定字段。可以在projection document中使用dot noation来引用指定的内嵌字段。
如下的示例返回:
_id
字段(默认会返回)item
字段status
字段size
中的uom
字段
从MongoDB 4.4版本开始,针对内嵌字段我们也可以使用内嵌形式,例如:
{ item: 1, status: 1, size: { uom: 1 } }
Suppress Specific Fields in Embedded Documents
我们可以抑制内嵌document的指定字段。使用dot notation来引用对应的字段,并将对应的字段值设置为0.
下面的例子指定一个projection,排除返回size
document中的uom
字段,而其他的字段均返回:
从MongoDB 4.4版本开始,针对内嵌字段我们也可以使用内嵌形式,例如:
{ item: 1, status: 1, size: { uom: 0 } }
Projection on Embedded Documents in an Array
使用dot notation数组中内嵌document的指定字段。
如下的例子返回指定字段:
_id
字段(默认会返回)item
字段status
字段instock
数组中内嵌document的qty
字段
Project Specific Array Elements in the Returned Array
对于包含数组的字段,MongoDB提供了如下的projection operator来操作数组:
如下的例子使用$slice这一projection operator来返回instock
数组中最后一个元素。
$elemMatch、$slice、$是仅有的三种可以筛选特定数组元素的方法。比如,你不能使用数组索引来筛选特定元素,eg: {"instock.0": 1}
这一projection不能
筛选数组的第一个元素。
Additional Considerations
从MongoDB 4.4版本开始,针对projection MongoDB会强制一些额外的限制,请参看Projection Restrictions。
3.5 Query for Null or Missing Fields
在MongoDB中不同的query operators对待null
值的方式也不同。
本文提供一些使用db.collection.find()方法查询null
值的示例。例子使用inventory
这个collection,我们向该collection填充一些数据:
Equality Filter
{item: null}
查询匹配item
字段的值为null
或者不含item
的document。
上述查询会返回inventory
集合中的两个元素。
Type Check
{ item : { $type: 10 } }
查询匹配含有item
字段且该字段值为null
的documents。比如,item
字段的值为BSON Type Null(其对应的type number为10):
上述查询只返回item字段值为null
的document。
Existence Check
下面的示例查询不含某一字段的documents。
注:从MongoDB 4.2版本开始,用户不能使用query filter
$type: 0
作为$exists: false
的等价。
{ item : { $exists: false } }
匹配不含item
字段的documents:
上述例子只返回不含item
字段的documents。
3.6 Iterate a Cursor in mongosh
db.collection.find()会返回一个游标
(cursor)。要访问这些documents,你需要遍历该cursor。然而,在mongosh中,假如返回的cursor没有赋值给一个使用var
关键字定义的变量时,则cursor会自动的遍历20次以打印结果集中最开头的20个documents。
下面的例子描述了一种方法可以手动(manually)的遍历cursor从而访问结果集中的documents,或者使用iterator index来访问结果集中的元素。
Manually Iterate the Cursor
在mongosh中,当你将find()方法返回的结果集赋值给一个由var
关键字定义的变量时,则cursor将不会自动的遍历。
你可以在mongosh中遍历该cursor多达20次,以打印结果集中的元素,请参看如下示例:
Note: You can set the
DBQuery.shellBatchSize
attribute to change the number of documents from the default value of 20.
你也可以使用cursor methodnext()来访问结果集中的元素,参看如下示例:
作为另一种打印方式,考虑printjson()
帮助方法以代替print(tojson())
:
另外,你也可以使用forEach()来遍历cursor,并访问其中的documents,参看如下示例:
Iterator Index
在mongosh中,你可以使用toArray()方法来遍历cursor,并通过一个数组来返回documents,参看如下:
toArray方法会将cursor所返回的所有documents加载到RAM。toArray()会exhausts cursor。
另外有一些Driver会针对cursor提供索引(index)来访问其中的documents(比如:cursor[index]
)。这仅仅知识调用toArray()的一种简写形式,然后在结果集数组上使用索引。
考虑下面的示例:
其中myCursor[1]
等价于如下:
Cursor Behaviors
1) Cursors Opened Within a Session
从MongoDB 5.0(以及4.4.8)版本开始,在一个client session中所创建的cursors会在对应的server session接收到killSessions命令后被关闭,或者遇到session超时,或者client已经exhausted对应的cursor。
默认情况下,server session的超时时间为30分钟。要改变该值,在启动mongod时请设置localLogicalSessionTimeoutMinutes参数。
2) Cursors Opened Outside of a Session
3) Cursor Isolation
4) Cursor Batches
Cursor Information
[参看]: