MongoDB-上一个和下一个内部子文档
我试图使用聚合框架从我的集合中获取3个子文档(我只想使用聚合,因为这是一个长管道的一部分)。 我只知道一个子文档的一个属性。我需要检索该MongoDB-上一个和下一个内部子文档,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我试图使用聚合框架从我的集合中获取3个子文档(我只想使用聚合,因为这是一个长管道的一部分)。 我只知道一个子文档的一个属性。我需要检索该子文档以及上一个和下一个子文档。 例如: 我只知道一个字幕顺序(例如,“11”),我需要获得如下内容: [ { "title": "Title 34", "subDoc": [ { "subtitle": "subtitle
子文档以及上一个和下一个子文档。
例如:
我只知道一个字幕顺序(例如,“11”),我需要获得如下内容:
[
{
"title": "Title 34",
"subDoc": [
{
"subtitle": "subtitle 8",
"order": 8
},
{
"subtitle": "subtitle 11",
"order": 11
},
{
"subtitle": "subtitle 13",
"order": 13
}
]
}
]
我试过使用“展开”、“顺序”、“限制”,但我只能获取上一个或下一个文档,不能同时获取这两个文档
游乐场:
如果您真的想通过聚合来实现,但结构已经修改,您可以在方便的时候映射它,我认为这是一个解决方案
db.collection.aggregate([
{
"$sort": {
"subDoc.order": 1
}
},
{
"$group": {
"_id": "$title",
"next": {
"$push": {
"$cond": [
{
"$gt": [
"$subDoc.order",
11
]
},
{
"id": "$_id",
"item": "$$CURRENT.subDoc"
},
"$$REMOVE"
]
}
},
"prev": {
"$push": {
"$cond": [
{
"$lt": [
"$subDoc.order",
11
]
},
{
"id": "$_id",
"item": "$$CURRENT.subDoc"
},
"$$REMOVE"
]
}
},
"current": {
"$push": {
"$cond": [
{
"$eq": [
"$subDoc.order",
11
]
},
{
"id": "$_id",
"item": "$$CURRENT.subDoc"
},
"$$REMOVE"
]
}
}
}
},
{
$project: {
_id: 1,
next: {
$slice: [
"$next",
1
]
},
prev: {
$slice: [
"$prev",
-1
]
},
current: 1
}
}
])
输出如下所示
[
{
"_id": "Title 34",
"current": [
{
"id": "33",
"item": {
"order": 11,
"subtitle": "subtitle 11"
}
}
],
"next": [
{
"id": "15",
"item": {
"order": 12,
"subtitle": "subtitle 12"
}
}
],
"prev": [
{
"id": "34",
"item": {
"order": 8,
"subtitle": "subtitle 8"
}
}
]
}
]
您可以使用以下阶段实现您的用例:
$sort thesubDoc.order
$将所有文档分组到一个数组中
查找上一个和当前数组元素的索引
$group基于标题
并使用$addToSet附加所需的文档
$project阶段将数据转换为预期输出
边缘案例考虑基于样本DOC:
没有以前的文件
例如:subDoc.order=6
,退货单[6,7]
没有当前文档
例如:subDoc.order=14
,返回空
没有下一份文件
例如:subDoc.order=13
,退货单[11,13]
当documentcount=1时,当前文档存在,但没有上一个或下一个文档
您可以使用以下聚合查询:
db.collection.aggregate([
{
"$sort": {
"subDoc.order": 1
}
},
{
$project: {
"title": 1,
"order": "$subDoc.order",
"subtitle": "$subDoc.subtitle"
}
},
{
$group: {
_id: null,
data: {
$push: "$$ROOT"
},
count: {
"$sum": 1
}
}
},
{
$addFields: {
"previousDoc": {
$subtract: [
{
$indexOfArray: [
"$data.order",
11
]
},
1
]
},
"nextDoc": {
$add: [
{
$indexOfArray: [
"$data.order",
11
]
},
1
]
},
currentDoc: {
$indexOfArray: [
"$data.order",
11
]
}
}
},
{
"$addFields": {
"next": {
$arrayElemAt: [
"$data",
"$nextDoc"
]
},
previous: {
$arrayElemAt: [
"$data",
"$previousDoc"
]
},
current: {
$arrayElemAt: [
"$data",
"$currentDoc"
]
}
}
},
{
$unwind: "$data"
},
{
$group: {
_id: "$data.title",
p: {
"$addToSet": {
$cond: [
{
$and: [
{
$lt: [
"$currentDoc",
1
]
},
]
},
"$$REMOVE",
"$previous"
]
}
},
c: {
"$addToSet": {
$cond: [
{
$and: [
{
$lt: [
"$currentDoc",
0
]
},
{
$ne: [
"$count",
1
]
}
]
},
"$$REMOVE",
"$current"
]
}
},
n: {
"$addToSet": {
$cond: [
{
$lt: [
"$nextDoc",
1
]
},
"$$REMOVE",
"$next"
]
}
},
}
},
{
$project: {
subDoc: {
"$concatArrays": [
"$p",
"$c",
"$n"
]
}
}
},
{
$project: {
"subDoc.subtitle": 1,
"subDoc.order": 1
}
}
])
你可以试试
$sort
按顺序
升序排序
$group
bytitle
并生成subDoc
对象数组和subDocOrder
订单字段数组
$addFields
添加三个字段prevOrder
上一个订单号($indeOfArray
获取上一个索引11并减去1)和nextOrder
下一个订单号($indeOfArray
获取下一个索引11并添加2),大小subDoc
子doc
数组的大小
显示必填字段,并获取$project
数组子文档
要从2个条件中获取范围,首先检查$range
是否小于0,然后返回0,否则prevOrder
,第二次检查preOrder
是否大于nextOrder
数组的大小,然后返回大小,否则返回subDoc
,最后我们得到了范围的起始数和结束数nextOrder
迭代我们要在map中输入的上述创建的范围数组的循环,签入将返回$map
表单范围数组$arrayElemAt
涵盖的测试用例:
子文档
只有一个当前元素,该怎么办?
(这将只返回单个当前元素)您可以将所有文档分组到一个数组中,然后找到您知道的数组元素的索引。这将为您提供上一个和下一个索引值以及元素。
db.collection.aggregate([
{
"$sort": {
"subDoc.order": 1
}
},
{
$project: {
"title": 1,
"order": "$subDoc.order",
"subtitle": "$subDoc.subtitle"
}
},
{
$group: {
_id: null,
data: {
$push: "$$ROOT"
},
count: {
"$sum": 1
}
}
},
{
$addFields: {
"previousDoc": {
$subtract: [
{
$indexOfArray: [
"$data.order",
11
]
},
1
]
},
"nextDoc": {
$add: [
{
$indexOfArray: [
"$data.order",
11
]
},
1
]
},
currentDoc: {
$indexOfArray: [
"$data.order",
11
]
}
}
},
{
"$addFields": {
"next": {
$arrayElemAt: [
"$data",
"$nextDoc"
]
},
previous: {
$arrayElemAt: [
"$data",
"$previousDoc"
]
},
current: {
$arrayElemAt: [
"$data",
"$currentDoc"
]
}
}
},
{
$unwind: "$data"
},
{
$group: {
_id: "$data.title",
p: {
"$addToSet": {
$cond: [
{
$and: [
{
$lt: [
"$currentDoc",
1
]
},
]
},
"$$REMOVE",
"$previous"
]
}
},
c: {
"$addToSet": {
$cond: [
{
$and: [
{
$lt: [
"$currentDoc",
0
]
},
{
$ne: [
"$count",
1
]
}
]
},
"$$REMOVE",
"$current"
]
}
},
n: {
"$addToSet": {
$cond: [
{
$lt: [
"$nextDoc",
1
]
},
"$$REMOVE",
"$next"
]
}
},
}
},
{
$project: {
subDoc: {
"$concatArrays": [
"$p",
"$c",
"$n"
]
}
}
},
{
$project: {
"subDoc.subtitle": 1,
"subDoc.order": 1
}
}
])
let order = 11;
db.collection.aggregate([
{ $sort: { "subDoc.order": 1 } },
{
$group: {
_id: "$title",
subDoc: { $push: "$subDoc" },
subDocOrder: { $push: "$subDoc.order" }
}
},
{
$addFields: {
prevOrder: {
$subtract: [{ $indexOfArray: ["$subDocOrder", order] }, 1]
},
nextOrder: {
$add: [{ $indexOfArray: ["$subDocOrder", order] }, 2]
},
sizeSubDoc: { $size: "$subDoc" }
}
},
{
$project: {
_id: 0,
title: "$_id",
subDoc: {
$cond: [
{ $in: [order, "$subDocOrder"] },
{
$map: {
input: {
$range: [
{ $cond: [{ $lt: ["$prevOrder", 0] }, 0, "$prevOrder"] },
{ $cond: [{ $gt: ["$nextOrder", "$sizeSubDoc"] }, "$sizeSubDoc", "$nextOrder"] }
]
},
in: { $arrayElemAt: ["$subDoc", "$$this"] }
}
},
[]
]
}
}
}
])