【问题标题】:Use dynamic object key as a `localField` and its value for `$lookup` aggregation stage使用动态对象键作为 `localField` 及其用于 `$lookup` 聚合阶段的值
【发布时间】:2023-02-12 12:17:46
【问题描述】:

我有一个架构:

// mongoose schema
const MySchema = new Schema({ objWithDynamicKeys: { type: Map, of: String } });

const OtherSchema = new Schema({
  limit: Number,
  refToMySchema: { type: Schema.Types.ObjectId, ref: 'MyModel' },
  name: String,
});

MySchema 模型的文档如下所示:

const doc = {
  _id: new ObjectId("some-string"),
  objWithDynamicKeys: {
    "62f74bcfd4aa7ff5c45c7fe3": 2,
    "62f74bcfd4aa7ff5c45c7fe4": 5,
    "62f74bcfd4aa7ff5c45c7fe5": 1,
}

OtherSchema 模型的文档如下所示:

const otherDoc1 = {
  _id: new ObjectId("62f74bcfd4aa7ff5c45c7fe3"),
  limit: 5,
  name: "First",
};
const otherDoc2 = {
  _id: new ObjectId("62f74bcfd4aa7ff5c45c7fe4"),
  limit: 5,
  name: "Second",
};
const otherDoc3 = {
  _id: new ObjectId("62f74bcfd4aa7ff5c45c7fe5"),
  limit: 3,
  name: "Third",
};

我正在构建一个聚合,它应该找到所有 OtherSchema 文档,其 _idMySchema 文档的 objWithDynamicKeys 中的键,其中 objWithDynamicKeys 的值小于相应文档的 limit

所以在运行聚合后我想要有以下输出:

[
  {
    _id: new ObjectId("62f74bcfd4aa7ff5c45c7fe3"), // doc1
    limit: 5,
    name: "First",
  },
  {
    _id: new ObjectId("62f74bcfd4aa7ff5c45c7fe5"), // doc3
    limit: 5,
    name: "Third",
  },
];

如果objWithDynamicKeys 是一个数组,那就没那么难了。

{
  $lookup: {
    from: 'othercollection',
    localField: 'objWithDynamicKeys',
    foreignField: '_id',
    as: 'out',
    pipeline: [
      {
        $match: {
          $expr: {
            $lt: ['$field_from_somewhere', '$limit'],
          },
        },
      },
    ],
  },
},

我怎样才能做到这一点?甚至有可能做吗?

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework mongoose-schema


    【解决方案1】:
    1. $set - 设置objWithDynamicKeys通过$objectToArray将键值对转换为数组。

    2. $unwind - 将 objWithDynamicKeys 数组解构为多个文档。

    3. $lookup- Join with *Other schema collection* by matching_idand less thanlimitconditions and returns the result asout` 数组。

    4. $match - 使用out 过滤文档不是空数组。

    5. $replaceWith - 用out 数组的第一个文档替换输入文档。

      MySchema.aggregate([
        {
          $set: {
            objWithDynamicKeys: {
              $objectToArray: "$objWithDynamicKeys"
            }
          }
        },
        {
          $unwind: "$objWithDynamicKeys"
        },
        {
          $lookup: {
            from: "/* Other Schema collection */",
            let: {
              key: {
                $toObjectId: "$objWithDynamicKeys.k"
              },
              value: "$objWithDynamicKeys.v"
            },
            as: "out",
            pipeline: [
              {
                $match: {
                  $expr: {
                    $and: [
                      {
                        $eq: [
                          "$$key",
                          "$_id"
                        ]
                      },
                      {
                        $lt: [
                          "$$value",
                          "$limit"
                        ]
                      }
                    ]
                  }
                }
              }
            ]
          }
        },
        {
          $match: {
            out: {
              $ne: []
            }
          }
        },
        {
          $replaceWith: {
            $first: "$out"
          }
        }
      ])
      

      Sample Mongo Playground

    【讨论】:

    • 您认为如果不先将对象转换为数组就无法直接处理对象吗?
    • 否。必须转换为数组才能获得具有 k 和 v 属性的文档。
    猜你喜欢
    • 2020-02-20
    • 2018-07-21
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    相关资源
    最近更新 更多