MongoDB 查询文档操作笔记

Mongo shell 读取文档操作

命令

  • db.collection.find()
  • 匹配查询
  • 操作操作符

游标:

  • 查询操作返回的结果游标
  • 游标的迭代与操作

投射

  • 只返回部分字段
  • 内嵌文档的投射
  • 数组的投射

命令:db.<collection>.find(<query>, <projection>)

  • <query> 定义读取文档的筛选条件, 使用 查询运算符 指定选择过滤器
  • <projection> 定义读取文档结果 投影

1. 既不筛选,也不投射

  • db.accounts.find()
  • db.accounts.find().pretty()
> db.accounts.find()
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }

> db.accounts.find().pretty()
{
	"_id" : {
		"accoountNo" : "001",
		"type" : "savings"
	},
	"name" : "irene",
	"balance" : 80
}
{
	"_id" : {
		"type" : "savings",
		"accoountNo" : "001"
	},
	"name" : "irene",
	"balance" : 80
}

2. 查询选择器

https://www.mongodb.com/docs/v6.0/reference/operator/query/

比较

名称 描述
$eq 匹配等于指定值的值。
$gt 匹配大于指定值的值。 (如果比较字符串,将按照字符排序)
$gte 匹配大于或等于指定值的值。
$in 匹配数组中指定的任何值。
$lt 匹配小于指定值的值。
$lte 匹配小于或等于指定值的值。
$ne 匹配所有不等于指定值的值。(不包含匹配字段的文档也会被匹配到)
$nin 不匹配数组中指定的任何值。 (不包含匹配字段的文档也会被匹配到)

使用实例:{field: {$gt: value}

> db.accounts.find()
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

> db.accounts.find({name: "bob"})
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }

> db.accounts.find({"_id.type": "savings"})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }

> db.accounts.find({"_id.type": {$ne: "savings"}})
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

> db.accounts.find({"_id.type": {$ne: "test"}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

逻辑

名称 描述 表达式
\(and | 用逻辑联接查询子句AND将返回两个子句都匹配的所有文档。 |{\)and: [
{},
{}
]}
\(not | 反转查询表达式的效果,并返回与查询表达式不匹配的文档。<br>(**不包含匹配字段的文档也会被匹配到**) | {field: {\)not: {}}}
$or | 用逻辑联接查询子句OR将返回符合任一子句条件的所有文档。
当筛选条件都是 $eq时, $or 与 $in 等效
{$or: [
{},
{}
]}
\(nor | 用逻辑联接查询子句NOR将返回两个子句均不匹配的所有文档。 <br>(**不包含匹配字段的文档也会被匹配到**)|{\)nor: [
{},
{}
]}
# 读取余额不小于90的银行账户文档
> db.accounts.find({balance: {$not: {$lt:90}}})
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

# 复合主键的type 不等于 'test' 的文档
> db.accounts.find({"_id.type": {$not: {$eq: "test"}}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }
>

# 复合主键的type 不等于 'savings' 的文档
> db.accounts.find({"_id.type": {$not: {$eq: "savings"}}})
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

# and 操作
> db.accounts.find({
    $and: [
        {balance: {$gte:90}}, 
        {name: {$lt: "bob"}}
    ] 
  })
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

# (不同字段)省略and操作
> db.accounts.find({
    balance: {$gte:90},  
    name: {$lt: "bob"}   
  })
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

# (同一字段)省略and操作
> db.accounts.find({
    balance: {$gt:80, $lt:100}
  })
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

元素

名称 描述 表达式
\(exists | 匹配具有指定字段的文档。 |{field: {\)exists: boolean }}
\(type | 如果字段是指定类型,则选择文档。[BSON Types](https://www.mongodb.com/docs/v6.0/reference/bson-types/) |{field: {\)type: BSON_type }}
{field: {$type: [BSON_type, BSON_type ...]}}
> db.accounts.find({"_id.type": {$exists: true}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }

> db.accounts.find({"_id.type": {$ne: "test"}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

> db.accounts.find({"_id.type": {$exists: true, $ne: "test"}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }

> db.accounts.find({"_id": {$type: "objectId"}})
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

> db.accounts.find({"_id": {$type: ["objectId", "object"]}})
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }

# 字段为空的文档
> db.accounts.find({"name": {$type: "null"}})

评估

名称 描述
$expr 允许在查询语言中使用聚合表达式。
$jsonSchema 根据给定的JSON Schema验证文档。
$mod 对字段的值执行模运算并选择具有指定结果的文档。
$regex 选择值与指定的正则表达式匹配的文档。
$text 执行文本搜索。
$where 匹配满足JavaScript表达式的文档。
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ <field>: { $regex: 'pattern', $options: '<options>' } }
{ <field>: { $regex: /pattern/<options> } }   # 在和 $in 操作符一起使用时,只能使用这一种

> db.accounts.find({name: {$in: [ /^J/, /^k/ ] }})
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }

> db.accounts.find({name: {$in: [ /^J/i, /^k/ ] }})
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

> db.accounts.find({name: { $regex: /ACK/}})
>
> db.accounts.find({name: { $regex: /ACK/, $options: 'i' }})
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

地理空间

名称 描述
$geoIntersects | 选择与GeoJSON几何形状相交的几何形状。该2dsphere索引支持 $geoIntersects。
$geoWithin | 选择边界GeoJSON几何内的几何。该2dsphere和2D指标支持 $geoWithin。
$near | 返回点附近的地理空间对象。需要地理空间索引。该2dsphere和2D指标支持 $near。
$nearSphere | 返回球体上某个点附近的地理空间对象。需要地理空间索引。该2dsphere和2D指标支持 $nearSphere。

数组

名称 描述
$all 匹配数组字段中包含所有查询值的文档
$elemMatch 匹配数组字段中至少存在一个值满足筛选条件的文档
$size 如果数组字段为指定大小,则选择文档。
> db.accounts.find()
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

# $all -> { <field>: { $all: [ < > , <value2> ... ] } }
> db.accounts.find({contact: { $all: ["Alabama", "US"] }})
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

> db.accounts.find({contact: { $all: [[ "222", "333" ]] }})
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }

# $elemMatch -> { <field>: { $elemMatch: { <query1>, <query2>, ... } } }
> db.accounts.find({contact: { $elemMatch: {$gte: "110", $lte: "120" }}})
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

# $all 和 $elemMatch 结合
# 查询 contact 中包含一个等于 "111" 和 一个等于 "US" 的文档
> db.accounts.find({
    contact: { $all: [
       {$elemMatch: {$eq: "111"}},
       {$elemMatch: {$eq: "US"}},
    ]}
})
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }

按位

名称 描述
$bitsAllClear 匹配其中一组位位置的数值或二进制值都具有值0。
$bitsAllSet 匹配其中一组位位置的数值或二进制值都具有值1。
$bitsAnyClear 匹配数字或二进制值,其中一组位位置中的任何位的值为0。
$bitsAnySet 匹配数字或二进制值,其中一组位位置中的任何位的值为1。

注释

名称 描述
$comment 向查询谓词添加注释。

3. 投影算子

名称 描述
$ 在与查询条件匹配的数组中投影第一个元素。
\(elemMatch | 投影与指定\)elemMatch条件匹配的数组中的第一个元素。
\(meta | 投影\)text操作期间分配的文档分数。
$slice 限制从数组投影的元素数量。支持跳过和限制切片。

文档游标

  • db.collection.find() 返回一个文档集合游标
  • 在不迭代游标的情况下,只列出前20个文档
  • 可以直接使用游标下标直接访问文档集合中的某一个文档
  • 遍历完游标中所有的文档后,或者在10分钟后,游标将自动关闭
  • 可以使用noCursorTimeout()函数来保持游标一直有效, 在这之后,在不遍历的情况下,需要主动关闭游标
> var myCursor = db.accounts.find()
> myCursor
{ "_id" : { "accoountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }
>
> myCursor
>
> var myCursor = db.accounts.find()
> myCursor[2]
{
	"_id" : ObjectId("6327179289c04594a4b8f675"),
	"name" : "bob",
	"balance" : 100
}
> myCursor[1]
{
	"_id" : {
		"type" : "savings",
		"accoountNo" : "001"
	},
	"name" : "irene",
	"balance" : 80
}

> var myCursor = db.accounts.find().noCursorTimeout()
> myCursor.close()

游标所有的方法:

游标函数 描述
cursor.hasNext() 如果游标包含文档并且可以迭代,则返回true。
cursor.next() 返回游标中的下一个文档。
cursor.forEach() 对光标中的每个文档应用JavaScript函数
cursor.limit() 和SQL中 limit 一样,注意: cursor.limit(0) 返回全部
cursor.skip() 和SQL中 offset 一样,返回一个游标,该游标仅在通过或跳过多个文档后才开始返回结果
cursor.count() 修改光标以返回结果集中的文档数,而不是文档本身
cursor.sort() 返回根据排序规范排序的结果。
cursor.close() 关闭游标并释放关联的服务器资源
cursor.allowDiskUse()
cursor.allowPartialResults()
cursor.batchSize()
cursor.isClosed()
cursor.collation()
cursor.comment()
cursor.explain()
cursor.hint()
cursor.isExhausted()
cursor.itcount()
cursor.map()
cursor.max()
cursor.maxTimeMS()
cursor.min()
cursor.noCursorTimeout()
cursor.objsLeftInBatch()
cursor.pretty()
cursor.readConcern()
cursor.readPref()
cursor.returnKey()
cursor.showRecordId()
cursor.size()
cursor.tailable()
cursor.toArray()
# sort -> { field: ordering }
# 在sort参数中指定要作为排序依据的一个或多个字段,以及的值1或-1分别指定升序或降序排序。
> db.accounts.find().sort({balance: -1, name: -1})
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob", "balance" : 100 }
{ "_id" : ObjectId("6329d655f5bd549a110fc5d1"), "name" : "clice", "balance" : 90 }
{ "_id" : ObjectId("6329d648f5bd549a110fc5d0"), "name" : "blice", "balance" : 90 }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice", "balance" : 90 }
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene", "balance" : 80 }

注意游标函数执行顺序:

  1. 无论语句的位置顺序如何,最终结果将会按照语句的优先级顺序执行: cursor.sort() > cursor.skip() > cursor.limit()

文档投影

命令:db.<collection>.find(<query>, <projection>)

  • <query> 定义读取文档的筛选条件, 使用 查询运算符 指定选择过滤器

  • <projection> 定义读取文档结果 投影

    不使用投影时,db.collection.find()返回符合筛选条件的完整文档。

    除了文档主键之外,我们不可以在投影文档中混合使用包含和不包含这两种投影。

    \(slice 操作符可以返回数组字段中的部分元素 \)elemMatch 和 $ 操作符可以返回数组字段中满足筛选条件的第一个元素, 注意 $ 作为操作符时,表示投影的筛选条件和 query 中相应字段的筛选条件一致,下面有例子

> db.accounts.find({}, {"name": 1})
{ "_id" : { "type" : "savings", "accoountNo" : "001" }, "name" : "irene" }
{ "_id" : ObjectId("6327179289c04594a4b8f675"), "name" : "bob" }
{ "_id" : ObjectId("632717a889c04594a4b8f676"), "name" : "alice" }
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen" }
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack" }
{ "_id" : ObjectId("6329d648f5bd549a110fc5d0"), "name" : "blice" }
{ "_id" : ObjectId("6329d655f5bd549a110fc5d1"), "name" : "clice" }
>
>
> db.accounts.find({}, {"name": 1, "_id": 0})
{ "name" : "irene" }
{ "name" : "bob" }
{ "name" : "alice" }
{ "name" : "karen" }
{ "name" : "jack" }
{ "name" : "blice" }
{ "name" : "clice" }

> db.accounts.find({}, {"name": 0, "_id": 0})
{ "balance" : 80 }
{ "balance" : 100 }
{ "balance" : 90 }
{ "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }
{ "balance" : 90 }
{ "balance" : 90 }

> db.accounts.find({}, {"name": 1, "balance": 0})
Error: error: {
	"ok" : 0,
	"errmsg" : "Cannot do exclusion on field balance in inclusion projection",
	"code" : 31254,
	"codeName" : "Location31254"
}

# $slice 操作符可以返回数组字段中的部分元素
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: 1}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ [ "222", "333" ] ] }
{ "name" : "jack", "contact" : [ "111" ] }
>
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: 2}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ [ "222", "333" ], "Beijing" ] }
{ "name" : "jack", "contact" : [ "111", "Alabama" ] }

> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: -1}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ "China" ] }
{ "name" : "jack", "contact" : [ "US" ] }

> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: -2}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ "Beijing", "China" ] }
{ "name" : "jack", "contact" : [ "Alabama", "US" ] }

# {$slice: [1, 2]} 表示跳过数组中的第 1 个元素后,返回 2 个元素
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: [1, 2]}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ "Beijing", "China" ] }
{ "name" : "jack", "contact" : [ "Alabama", "US" ] }

# {$slice: [1, 2]} 表示跳过数组中的第 1 个元素后,返回 1 个元素
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: [1, 1]}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ "Beijing" ] }
{ "name" : "jack", "contact" : [ "Alabama" ] }

# {$slice: [1, 2]} 表示跳过数组中的第 2 个元素后,返回 1 个元素
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$slice: [2, 1]}}).sort({contact: -1}).limit(2)
{ "name" : "karen", "contact" : [ "China" ] }
{ "name" : "jack", "contact" : [ "US" ] }

# $elemMatch 和 $ 操作符可以返回数组字段中满足筛选条件的第一个元素, 注意 $ 作为操作符时,表示投影的筛选条件和 query 中相应字段的筛选条件一致
> db.accounts.find({}, {"_id": 0, "name": 1, "contact": {$elemMatch: {$gt: "Alabama"}}})
{ "name" : "irene" }
{ "name" : "bob" }
{ "name" : "alice" }
{ "name" : "karen", "contact" : [ "Beijing" ] }
{ "name" : "jack", "contact" : [ "US" ] }
{ "name" : "blice" }
{ "name" : "clice" }

> db.accounts.find({contact: {$gt: "Alabama"}})
{ "_id" : ObjectId("632873b543489401f4ff49c2"), "name" : "karen", "balance" : 250, "contact" : [ [ "222", "333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("63287530f8526f895273d037"), "name" : "jack", "balance" : 1000, "contact" : [ "111", "Alabama", "US" ] }
>
> db.accounts.find({contact: {$gt: "Alabama"}}, {"_id": 0, "name": 1, "contact.$": 1})
{ "name" : "karen", "contact" : [ "Beijing" ] }
{ "name" : "jack", "contact" : [ "US" ] }
posted @ 2022-10-12 00:55  郭赫伟  阅读(127)  评论(0编辑  收藏  举报