$slice(投影)
定义
$slice
$slice
投影操作符指定了要在查询结果中返回的数组中的元素数。
语法
$slice
采用以下语法形式之一:
db.collection.find( <query>, { <arrayField>: { $slice: <number> } } );
or
db.collection.find( <query>, { <arrayField>: { $slice: [ <number>, <number> ] } } );
值 | 说明 |
---|---|
| 指定了要在
如果 |
| 指定从第一个元素开始跳过指定数量的元素后要在 对于
对于 |
行为
$slice
嵌入式数组
当投影属于包含投影的一部分时,嵌套文档中数组的 $slice
投影不再返回嵌套文档中的其他字段。
例如,考虑一个文档集合 inventory
,其中的文档包含 size
字段:
{ item: "socks", qty: 100, details: { colors: [ "blue", "red" ], sizes: [ "S", "M", "L"] } }
以下操作仅使用 colors
数组的指定切片来投影 _id
字段(默认)、qty
字段和 details
字段:
db.inventory.find( { }, { qty: 1, "details.colors": { $slice: 1 } } )
换言之,该操作会返回以下文档:
{ "_id" : ObjectId("5ee92a6ec644acb6d13eedb1"), "qty" : 100, "details" : { "colors" : [ "blue" ] } }
如果 $slice
投影是排除投影的一部分,则该操作将继续返回嵌套文档中的其他字段。也就是说,以下投影是排除投影。投影会排除 _id
字段以及 colors
数组中位于指定切片之外的元素,并返回所有其他字段。
db.inventory.find( { }, { _id: 0, "details.colors": { $slice: 1 } } )
{ "item" : "socks", "qty" : 100, "details" : { "colors" : [ "blue" ], "sizes" : [ "S", "M", "L" ] } }
$slice
投影自身被认为一种排除操作。
在以前的版本中,$slice
投影还包括嵌套文档中的其他字段,而无论该投影是包含性投影还是排除性投影。
查看限制
针对视图的 db.collection.find()
操作不支持 $slice
投影运算符。
$
位置操作符和$slice
限制
find
和 findAndModify
投影不能包含 $slice
投影表达式作为 $
投影表达式的一部分。
例如,以下操作无效:
db.inventory.find( { "instock.qty": { $gt: 25 } }, { "instock.$": { $slice: 1 } } )
在之前的版本中,MongoDB 返回instock
数组中符合查询条件的第一个元素( instock.$
);即位置投影"instock.$"
优先,而$slice:1
是无需操作。"instock.$": {
$slice: 1 }
不排除任何其他文档字段。
$slice
路径冲突:数组和嵌入式字段的
find
和 findAndModify
投影不能同时包含数组的 $slice
和嵌入数组的字段。
例如,考虑包含数组字段 instock
的集合 inventory
:
{ ..., instock: [ { warehouse: "A", qty: 35 }, { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ], ... }
以下操作失败并显示 Path
collision
错误:
db.inventory.find( {}, { "instock": { $slice: 1 }, "instock.warehouse": 0 } )
在以前的版本中,投影应用两个投影并返回instock
数组中的第一个元素 ($slice: 1
),但抑制投影元素中的warehouse
字段。从 MongoDB 4.4 开始,要获得相同的结果,请使用具有两个独立 $project
阶段的 db.collection.aggregate()
方法。
示例
创建一个包含以下文档的集合 posts
:
db.posts.insertMany([ { _id: 1, title: "Bagels are not croissants.", comments: [ { comment: "0. true" }, { comment: "1. croissants aren't bagels."} ] }, { _id: 2, title: "Coffee please.", comments: [ { comment: "0. fooey" }, { comment: "1. tea please" }, { comment: "2. iced coffee" }, { comment: "3. cappuccino" }, { comment: "4. whatever" } ] } ])
返回包含前 3 个元素的数组
以下操作使用 comments
数组上的 $slice
投影运算符来返回数组及其前三个元素。如果数组的元素少于三个,则返回数组中的所有元素。
db.posts.find( {}, { comments: { $slice: 3 } } )
该操作将返回以下文档:
{ "_id" : 1, "title" : "Bagels are not croissants.", "comments" : [ { "comment" : "0. true" }, { "comment" : "1. croissants aren't bagels." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "0. fooey" }, { "comment" : "1. tea please" }, { "comment" : "2. iced coffee" } ] }
返回包含前 3 个元素的数组
以下操作使用 comments
数组上的 $slice
投影操作符来返回数组及其最后三个元素。如果数组的元素少于三个,则返回数组中的所有元素。
db.posts.find( {}, { comments: { $slice: -3 } } )
该操作将返回以下文档:
{ "_id" : 1, "title" : "Bagels are not croissants.", "comments" : [ { "comment" : "0. true" }, { "comment" : "1. croissants aren't bagels." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "2. iced coffee" }, { "comment" : "3. cappuccino" }, { "comment" : "4. whatever" } ] }
跳过第一个元素后返回一个包含 3 个元素的数组
以下操作使用 comments
数组上的 $slice
投影操作符:
跳过第一个元素,从而使第二个元素成为起点。
然后,从起点开始返回三个元素。
如果跳转后数组中的元素少于三个,则会返回所有剩余元素。
db.posts.find( {}, { comments: { $slice: [ 1, 3 ] } } )
该操作将返回以下文档:
{ "_id" : 1, "title" : "Bagels are not croissants.", "comments" : [ { "comment" : "1. croissants aren't bagels." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "1. tea please" }, { "comment" : "2. iced coffee" }, { "comment" : "3. cappuccino" } ] }
跳过最后一个元素后返回一个包含 3 个元素的数组
以下操作使用 comments
数组上的 $slice
投影操作符来
从第一个元素向后跳转,从而以最后一个元素为起点。
然后,从起点开始返回三个元素。
如果跳转后数组中的元素少于三个,则会返回所有剩余元素。
db.posts.find( {}, { comments: { $slice: [ -1, 3 ] } } )
该操作将返回以下文档:
{ "_id" : 1, "title" : "Bagels are not croissants.", "comments" : [ { "comment" : "1. croissants aren't bagels." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "4. whatever" } ] }