MongoDB - 生成动态 $ 或使用管道变量?

问题描述 投票:0回答:1

希望有人可以提供帮助,因为我真的陷入困境!

我有这个疑问

SwapModel.aggregate([
    {
        $match: {
            organisationId: mongoose.Types.ObjectId(organisationId),
            matchId: null,
            matchStatus: 0,
            offers: {
                $elemMatch: {
                    from: { $lte: new Date(from) },
                    to: { $gte: new Date(to) },
                    locations: { $elemMatch: { $eq: location } },
                    types: { $elemMatch: { $eq: type } },
                },
            },
//problem is HERE
            $or: {
                $map: {
                    input: "$offers",
                    as: "offer",
                    in: {
                        from: { $gte: new Date("$$offer.from") },
                        to: { $lte: new Date("$$offer.to") },
                        location: { $in: "$$offer.locations" },
                        type: { $in: "$$offer.types" },
                    },
                },
            },
        },
    },
    { ...swapUserLookup },
    { $unwind: "$matchedUser" },
    { $sort: { from: 1, to: 1 } },
]);

我正在尝试使用

$match
文档的结果来生成
$or
的数组。我的数据如下所示:

[{
    _id: ObjectId("id1"),
    from: ISODate("2023-01-21T06:30:00.000Z"),
    to: ISODate("2023-01-21T18:30:00.000Z"),
    matchStatus: 0,
    matchId: null,
    userId: ObjectId("ddbb8f3c59cf13467cbd6a532"),
    organisationId: ObjectId("246afaf417be1cfdcf55792be"),
    location: "Chertsey",
    type: "DCA",
    offers: [{
        from: ISODate("2023-01-23T05:00:00.000Z"),
        to: ISODate("2023-01-24T07:00:00.000Z"),
        locations: ["Chertsey", "Walton"],
        types: ["DCA", "SRV"],
    }]
}, {
    _id: ObjectId("id2"),
    from: ISODate("2023-01-23T06:30:00.000Z"),
    to: ISODate("2023-01-23T18:30:00.000Z"),
    matchStatus: 0,
    matchId: null,
    userId: ObjectId("d6f10351dd8cf3462e3867f56"),
    organisationId: ObjectId("246afaf417be1cfdcf55792be"),
    location: "Chertsey",
    type: "DCA",
    offers: [{
        from: ISODate("2023-01-21T05:00:00.000Z"),
        to: ISODate("2023-01-21T07:00:00.000Z"),
        locations: ["Chertsey", "Walton"],
        types: ["DCA", "SRV"],
    }]
}]

我希望 $or 匹配所有具有相应的 from/to/location/type 作为当前文档的文档 - 这个想法是可以交换的两个班次

如果报价已知(作为数组传递给调用

aggregate
的函数),我可以通过以下方式执行此操作:

$or: offers.map((x) => ({
            from: { $gte: new Date(x.from) },
            to: { $lte: new Date(x.to) },
            location: { $in: x.locations },
            type: { $in: x.types },
        }))

但是我希望能够在聚合管道中执行此操作,而

offers
只能从当前文档中得知,
$offers

这可能吗?我已经尝试过

$in, $map, $lookup, $filter, $getField
但无法正确执行并且无法从 Google 获得任何内容,因为它认为我想要 $in(这与我需要的相反)。

我对 MongoDB 还很陌生,我的做法可能完全错误,但我真的很感激任何帮助!

编辑:预期输出只是一个匹配文档的数组,因此将文档 id1 传递给函数将返回一个包含 id2 的数组,因为每个文档都与另一个文档兼容

///expected output, from and to are between an offer in id1's from and to, similarly types/locations are compatible
{
    _id: ObjectId("id2"),
    from: ISODate("2023-01-23T06:30:00.000Z"),
    to: ISODate("2023-01-23T18:30:00.000Z"),
    matchStatus: 0,
    matchId: null,
    userId: ObjectId("d6f10351dd8cf3462e3867f56"),
    organisationId: ObjectId("246afaf417be1cfdcf55792be"),
    location: "Chertsey",
    type: "DCA",
    offers: [{
        from: ISODate("2023-01-21T05:00:00.000Z"),
        to: ISODate("2023-01-21T07:00:00.000Z"),
        locations: ["Chertsey", "Walton"],
        types: ["DCA", "SRV"],
    }]

解决方案

根据接受的答案,我能够创建自我查找,缺少的组件是使用

$anyElementTrue
搜索
offers
字段

的相互匹配

我怀疑有更优化的方法

Mongo Playground 工作示例

db.swaps.aggregate([
    {
        $match: {},
    },
    {
        $unwind: "$offers",
    },
    {
        $lookup: {
            from: "swaps",
            as: "matches",
            let: {
                parentId: "$_id",
                parentOrganisationId: "$organisationId",
                parentUserId: "$userId",
                parentLocations: "$offers.locations",
                parentTypes: "$offers.types",
                parentOffersFrom: "$offers.from",
                parentFrom: "$from",
                parentTo: "$to",
                parentOffersTo: "$offers.to",
                parentLocation: "$location",
                parentType: "$type",
            },
            pipeline: [
                {
                    $match: {
                        matchStatus: 0,
                        matchId: null,
                        $expr: {
                            $and: [
                                {
                                    $ne: ["$_id", "$$parentId"],
                                },
                                {
                                    $ne: ["$userId", "$$parentUserId"],
                                },
                                {
                                    $eq: [
                                        "$organisationId",
                                        "$$parentOrganisationId",
                                    ],
                                },
                                {
                                    $in: ["$location", "$$parentLocations"],
                                },
                                {
                                    $in: ["$type", "$$parentTypes"],
                                },
                                {
                                    $lte: ["$$parentOffersFrom", "$from"],
                                },
                                {
                                    $gte: ["$$parentOffersTo", "$to"],
                                },
                                {
                                    $anyElementTrue: {
                                        $map: {
                                            input: "$offers",
                                            as: "offer",
                                            in: {
                                                $and: [
                                                    {
                                                        $in: [
                                                            "$$parentLocation",
                                                            "$$offer.locations",
                                                        ],
                                                    },
                                                    {
                                                        $in: [
                                                            "$$parentType",
                                                            "$$offer.types",
                                                        ],
                                                    },
                                                    {
                                                        $lte: [
                                                            "$$offer.from",
                                                            "$$parentFrom",
                                                        ],
                                                    },
                                                    {
                                                        $gte: [
                                                            "$$offer.to",
                                                            "$$parentTo",
                                                        ],
                                                    },
                                                ],
                                            },
                                        },
                                    },
                                },
                            ],
                        },
                    },
                },
                {
                    $lookup: {
                        from: "users",
                        localField: "userId",
                        foreignField: "_id",
                        as: "matchedUser",
                    },
                },
                {
                    $set: {
                        matchedUser: {
                            $ifNull: [
                                {
                                    $first: "$matchedUser",
                                },
                                null,
                            ],
                        },
                    },
                },
            ],
        },
    },
    {
        $group: {
            _id: "$_id",
            doc: {
                $first: "$$ROOT",
            },
            matches: {
                $push: "$matches",
            },
            offers: {
                $push: "$offers",
            },
        },
    },
    {
        $set: {
            matches: {
                $reduce: {
                    input: "$matches",
                    initialValue: [],
                    in: {
                        $concatArrays: ["$$value", "$$this"],
                    },
                },
            },
        },
    },
    {
        $replaceRoot: {
            newRoot: {
                $mergeObjects: [
                    "$doc",
                    {
                        matches: "$matches",
                        offers: "$offers",
                    },
                ],
            },
        },
    },
    {
        $lookup: {
            from: "users",
            localField: "userId",
            foreignField: "_id",
            as: "user",
        },
    },
    {
        $set: {
            user: {
                $ifNull: [
                    {
                        $first: "$user",
                    },
                    null,
                ],
            },
        },
    },
    {
        $sort: {
            _id: 1,
        },
    },
]);
javascript node.js mongodb mongoose aggregation-framework
1个回答
1
投票

您可以根据子管道中设置的条件进行自查找。

db.collection.aggregate([
  {
    $match: {
      organisationId: "organisationId1",
      matchId: null,
      matchStatus: 0
    }
  },
  {
    $unwind: "$offers"
  },
  {
    "$lookup": {
      "from": "collection",
      "let": {
        offersFrom: "$offers.from",
        offersTo: "$offers.to",
        offersLocation: "$offers.locations",
        offersType: "$offers.types"
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $gte: [
                    "$from",
                    "$$offersFrom"
                  ]
                },
                {
                  $lte: [
                    "$to",
                    "$$offersTo"
                  ]
                },
                {
                  "$in": [
                    "$location",
                    "$$offersLocation"
                  ]
                },
                {
                  "$in": [
                    "$type",
                    "$$offersType"
                  ]
                },
                
              ]
            }
          }
        }
      ],
      "as": "selfLookup"
    }
  },
  {
    "$unwind": "$selfLookup"
  },
  {
    "$replaceRoot": {
      "newRoot": "$selfLookup"
    }
  }
])

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.