如何解决MongoDB-上一个和下一个内部子文档
我正在尝试使用聚合框架从我的集合中获取3个子文档(我只想使用聚合,因为这是长管道的一部分)。
我只知道一个子文档的一个属性。我还需要检索该subdoc
以及上一个和下一个。
示例:
[
{
"title": "Title 34","subDoc": {
"subtitle": "subtitle 8","order": 8
}
},{
"title": "Title 34","subDoc": {
"subtitle": "subtitle 6","order": 6
}
},"subDoc": {
"subtitle": "subtitle 11","order": 11
}
},"subDoc": {
"subtitle": "subtitle 13","order": 13
}
},"subDoc": {
"subtitle": "subtitle 7","order": 7
}
}
]
我只知道一个字幕顺序(例如,“ 11”),我需要获取以下内容:
[
{
"title": "Title 34","subDoc": [
{
"subtitle": "subtitle 8","order": 8
},{
"subtitle": "subtitle 11","order": 11
},{
"subtitle": "subtitle 13","order": 13
}
]
}
]
我尝试了展开,排序,限制,但是我只能获取上一个或下一个文档,而不能同时获取两个文档。
这里的游乐场: https://mongoplayground.net/p/0228GD-b6oZ
解决方法
您可以通过以下步骤实现用例:
- 对
subDoc.order
进行$ sort
- 将所有文档分组到一个数组中
- 查找先前和当前数组元素的索引
- $ group基于
title
,并使用$ addToSet附加必需的文档 - $ project阶段将数据转换为预期的输出
基于示例文档要考虑的边际案例:
- 没有先前的文件 例如:
subDoc.order=6
,返回文档[6,7]- 没有当前文档 例如:
subDoc.order= 14
,返回空- 没有下一个文档 例如:
subDoc.order= 13
,返回文档[11,13]document count=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",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
]
}
]
},"$current"
]
}
},n: {
"$addToSet": {
$cond: [
{
$lt: [
"$nextDoc",1
]
},"$next"
]
}
},}
},{
$project: {
subDoc: {
"$concatArrays": [
"$p","$c","$n"
]
}
}
},{
$project: {
"subDoc.subtitle": 1,"subDoc.order": 1
}
}
])
,
您可以尝试
-
$sort
由order
升序 -
$group
乘title
,并制作subDoc
对象数组和subDocOrder
订单字段数组 -
$addFields
添加三个字段,prevOrder
前一个订单号($indeOfArray
获得前一个索引11并减去1)和nextOrder
下一个订单号({{1} }以获得下一个索引11并加2),$indeOfArray
大小为sizeSubDoc
数组
subDoc
-
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",2] },sizeSubDoc: { $size: "$subDoc" } } },
以显示必填字段,并获取$project
数组 -
subDoc
从2个条件中获取范围,首先检查$range
小于0,然后返回0,否则返回prevOrder
,第二个检查preOrder
大于{的大小{1}}数组,然后返回大小,否则返回nextOrder
,最后我们得到范围的开始号和结束号 -
subDoc
迭代我们要在地图中输入的上述创建的范围数组的循环,然后检入将返回nextOrder
形式的范围数组
$map
涵盖的测试用例:
,
- 如果当前元素是第一个元素,意味着没有上一个元素怎么办? (这将仅返回当前元素和下一个元素)
- 如果当前元素是最后一个元素,意味着没有下一个元素怎么办? (这将仅返回当前和先前的元素)
- 如果
$arrayElemAt
仅具有一个当前元素怎么办? (这将仅返回单个当前元素)- 找不到您输入的11是什么? (这将返回空白数组)
我认为这是解决方案,如果您确实想通过聚合来实现,但是结构已修改,则可以在方便时进行映射
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","current": {
"$push": {
"$cond": [
{
"$eq": [
"$subDoc.order","$$REMOVE"
]
}
}
}
},{
$project: {
_id: 1,next: {
$slice: [
"$next",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"
}
}
]
}
]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。