Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB-上一个和下一个内部子文档_Mongodb_Aggregation Framework - Fatal编程技术网

MongoDB-上一个和下一个内部子文档

MongoDB-上一个和下一个内部子文档,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我试图使用聚合框架从我的集合中获取3个子文档(我只想使用聚合,因为这是一个长管道的一部分)。 我只知道一个子文档的一个属性。我需要检索该子文档以及上一个和下一个子文档。 例如: 我只知道一个字幕顺序(例如,“11”),我需要获得如下内容: [ { "title": "Title 34", "subDoc": [ { "subtitle": "subtitle

我试图使用聚合框架从我的集合中获取3个子文档(我只想使用聚合,因为这是一个长管道的一部分)。 我只知道一个子文档的一个属性。我需要检索该
子文档以及上一个和下一个子文档。
例如:

我只知道一个字幕顺序(例如,“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 the
    subDoc.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
      by
      title
      并生成
      subDoc
      对象数组和
      subDocOrder
      订单字段数组
    • $addFields
      添加三个字段
      prevOrder
      上一个订单号(
      $indeOfArray
      获取上一个索引11并减去1)和
      nextOrder
      下一个订单号(
      $indeOfArray
      获取下一个索引11并添加2),
      大小subDoc
      子doc
    数组的大小
    • $project
      显示必填字段,并获取
      子文档
      数组
    • $range
      要从2个条件中获取范围,首先检查
      prevOrder
      是否小于0,然后返回0,否则
      preOrder
      ,第二次检查
      nextOrder
      是否大于
      subDoc
      数组的大小,然后返回大小,否则返回
      nextOrder
      ,最后我们得到了范围的起始数和结束数
    • $map
      迭代我们要在map中输入的上述创建的范围数组的循环,签入将返回
      $arrayElemAt
      表单范围数组


    涵盖的测试用例:

  • 如果当前元素是第一个元素意味着没有前一个元素,该怎么办? (这将仅返回当前和下一个元素)
  • 如果当前元素是最后一个元素意味着没有下一个元素呢? (这将仅返回当前和以前的元素)
  • 如果
    子文档
    只有一个当前元素,该怎么办? (这将只返回单个当前元素)
  • 什么是您的输入11未找到? (这将返回空白数组)

  • 您可以将所有文档分组到一个数组中,然后找到您知道的数组元素的索引。这将为您提供上一个和下一个索引值以及元素。
    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"] }
                }
              },
              []
            ]
          }
        }
      }
    ])