javascript - MongoDB聚合: Replacing an array of IDs with the corresponding objects from an array in the same document

标签 javascript arrays mongodb aggregation-framework

我在一个集合中有以下文档:

[{
    id: 1,
    name: 'My document 1',
    allItems: [{
        id: 'item1',
        name: 'My item 1'
    }, {
        id: 'item2',
        name: 'My item 2'
    }, {
        id: 'item3'
        name: 'My item 3'
    }],
    containers: [{
        id: 'container1',
        selectedItems: [
            'item3',
            'item1'
        ]
    }, {
        id: 'container2',
        selectedItems: [
            'item3'
        ]
    }]
},
...]
我现在想编写一个查询来查找具有特定容器 ID(即 container1 )的文档并将其返回,同时将其转换为 selectedItems数组来保存 allItems 中的实际对象值同一文档的数组。
我想得到这个文件:
{
    id: 1,
    name: 'My document 1',
    container: {
        id: 'container1',
        selectedItems: [{
            id: 'item3'
            name: 'My item 3'
        }, {
            id: 'item1',
            name: 'My item 1'
        }
    }
}
目前我有以下聚合(Node.js):
db.collection.aggregate([{
    $match: {'containers.id': 'container1'},
    $addFields: {
        container: {
            $filter: {
                input: '$containers', 
                as: 'container', 
                cond: {
                    $eq: ['$$container.id', 'container1']
                }
            }
        }
    },
    $project: {containers: 0},
    $unwind: {path: '$container'}

    // I now have a new property "container" with the correct subdocument from the array
    // and removed the original array with all containers.
    // I now need a stage here to populate the container subdocuments in the `selectedItems` array

    $project: {allItems: 0} // remove the list of all items when not needed anymore in a following stage
}]);
我知道有$lookup ,但由于我想从同一个文档(不是不同的集合)中填充匹配的数组项,我想我不需要它。即使在 $lookup 中指定相同的集合,它将使用我的集合的根文档填充数组,并且展开和匹配子文档所需的属性将变得非常复杂。
我想过自己做一个items集合,但我需要在那里进行较慢的查找,并且我的数据不需要具有这些关系。
我希望我的问题很清楚,我很感谢我能得到的任何帮助!
我正在对我的真实数据进行一些额外的转换,比如从原始根文档中复制一些属性并隐藏其他属性,但这并不重要。
再次感谢你!

最佳答案

  • $match您的条件
  • $filter迭代 containers 的循环数组和过滤器id
  • $arrayElemAt从上面的过滤结果中选择第一个元素
  • $let声明一个变量并存储上述过程并存储结果
  • $filter迭代 allItems 的循环根据上述结果排列和过滤项目
  • db.collection.aggregate([
      { $match: { "containers.id": "container1" } },
      {
        $project: {
          name: 1,
          container: {
            $let: {
              vars: {
                container: {
                  $arrayElemAt: [
                    {
                      $filter: {
                        input: "$containers",
                        cond: { $eq: ["$$this.id", "container1"] }
                      }
                    },
                    0
                  ]
                }
              },
              in: {
                id: "$$container.id",
                selectedItems: {
                  $filter: {
                    input: "$allItems",
                    cond: { $in: ["$$this.id", "$$container.selectedItems"] }
                  }
                }
              }
            }
          }
        }
      }
    ])
    
    Playground

    第二个版本,你可以分阶段做流程,
  • $match您的条件
  • $filter迭代 containers 的循环数组和过滤器id
  • $arrayElemAt从上面的过滤结果中选择第一个元素
  • $filter迭代 allItems 的循环通过 selectedItems 排列和过滤项目
  • $$REMOVE将删除字段
  • db.collection.aggregate([
      { $match: { "containers.id": "container1" } },
      {
        $addFields: {
          containers: "$$REMOVE",
          container: {
            $arrayElemAt: [
              {
                $filter: {
                  input: "$containers",
                  cond: { $eq: ["$$this.id", "container1"] }
                }
              },
              0
            ]
          }
        }
      },
      {
        $addFields: {
          allItems: "$$REMOVE",
          "container.selectedItems": {
            $filter: {
              input: "$allItems",
              cond: { $in: ["$$this.id", "$container.selectedItems"] }
            }
          }
        }
      }
    ])
    
    Playground

    关于javascript - MongoDB聚合: Replacing an array of IDs with the corresponding objects from an array in the same document,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68833646/

    相关文章:

    c++ - 如何使用for循环C++将不同的值输入到二维指针到指针数组中

    arrays - Google Sheets 公式可跟踪过去 4 周内事件发生的数量

    mongodb - 如果日期在 mongodb 中为字符串格式,则使用 $gte 和 &lte mongo 运算符

    node.js - 转换发布带有显示次数的 MeteorJS

    javascript - 如何解决无限重新渲染问题?

    javascript - 如何设置可以缩放和拖动的背景图片?

    c - 在 C 中使用带有 for 循环的数组

    javascript - 设备之间同步 - 如何做到这一点?

    javascript - 您可以使用 python 中的映射或其他高阶函数来跟踪索引吗?

    javascript - 使用 angular 从 Node.js 调用多个 Action