希望有人可以提供帮助,因为我真的陷入困境!
我有这个疑问
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
字段 的相互匹配
我怀疑有更优化的方法
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,
},
},
]);
您可以根据子管道中设置的条件进行自查找。
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"
}
}
])