Mongodb Mongo聚合根据在另一个表中是否找到一个表中的记录排除这些记录
公寓桌Mongodb Mongo聚合根据在另一个表中是否找到一个表中的记录排除这些记录,mongodb,aggregation-framework,Mongodb,Aggregation Framework,公寓桌 { "_id": "AAA", "name": "Apartment AAA" }, { "_id": "BBB", "name": "Apartment BBB" }, { "_id": "CCC", "name": "Apartment CCC" }, { "_id": "DDD", "name": "Apartment DDD" }, { "_id": "EEE", "name": "Apartment
{
"_id": "AAA",
"name": "Apartment AAA"
},
{
"_id": "BBB",
"name": "Apartment BBB"
},
{
"_id": "CCC",
"name": "Apartment CCC"
},
{
"_id": "DDD",
"name": "Apartment DDD"
},
{
"_id": "EEE",
"name": "Apartment EEE"
}
{
"_id": 1,
"apartmentID": "AAA",
"checkin": 1490000000,
"checkout": 1499000000
}
{
"_id": 2,
"apartmentID": "BBB",
"checkin": 1500000000,
"checkout": 1590000000
}
{
"_id": 3,
"apartmentID": "CCC",
"checkin": 1490000000,
"checkout": 1499000000
}
{
"_id": 4,
"apartmentID": "DDD",
"checkin": 1500000000,
"checkout": 1590000000
}
预订表
{
"_id": "AAA",
"name": "Apartment AAA"
},
{
"_id": "BBB",
"name": "Apartment BBB"
},
{
"_id": "CCC",
"name": "Apartment CCC"
},
{
"_id": "DDD",
"name": "Apartment DDD"
},
{
"_id": "EEE",
"name": "Apartment EEE"
}
{
"_id": 1,
"apartmentID": "AAA",
"checkin": 1490000000,
"checkout": 1499000000
}
{
"_id": 2,
"apartmentID": "BBB",
"checkin": 1500000000,
"checkout": 1590000000
}
{
"_id": 3,
"apartmentID": "CCC",
"checkin": 1490000000,
"checkout": 1499000000
}
{
"_id": 4,
"apartmentID": "DDD",
"checkin": 1500000000,
"checkout": 1590000000
}
我需要找到所有在“1510000000
”和“1520000000
”之间没有预订的“name
”公寓
在这种情况下,结果应为:
{
"name": "Apartment AAA"
},
{
"name": "Apartment CCC"
},
{
"name": "Apartment EEE"
}
请注意,EEE公寓没有任何预订
通常我会将所有属性放入一个数组,然后将所有预订放入一个数组,然后在javascript中运行一些循环以查找可用的公寓
问题:是否有一种方法可以在一个mongodb聚合管道中实现这一点,并且只返回可用公寓的“名称”
我以前的查找:
db.apartment.aggregate([
{
$match: {}
},
{
$project: {
"name": 1
}
}
db.booking.aggregate([
{
$match: {
checkin: {$lte: 1520000000},
checkout: {$gte: 1510000000}
}
},
{
$project: {
"apartmentID": 1
}
}
从3.2版开始,您可以使用运算符外部联接两个集合:
db.apartment.aggregate([
{
$lookup: {
from: "booking",
localField: "_id",
foreignField: "apartmentID",
as: "booking"
}
},
{
$unwind: { path: "$booking", preserveNullAndEmptyArrays: true }
},
{
$match: {
$or: [
{ "booking": {$exists: false }},
{ "booking.checkin": {$gte: 1520000000} },
{ "booking.checkout": {$lte: 1510000000} }
]
}
},
{
$group: { _id: "$name" }
},
{
$project: { _id: 0, name: "$_id" }
}
])
输出:
{
"name" : "Apartment AAA"
},
{
"name" : "Apartment CCC"
},
{
"name" : "Apartment EEE"
}
详情: 第一阶段创建了公寓与预订的外部连接。此阶段产生的结果如下所示:
{
"_id": "AAA",
"name": "Apartment AAA",
"booking": [
{
"_id": 1,
"apartmentID": "AAA",
"checkin": 1490000000,
"checkout": 1499000000
},
{
"_id": 5,
"apartmentID": "AAA",
"checkin": 1500000000,
"checkout": 1590000000
},
]
}
...
{
"_id": "EEE",
"name": "Apartment EEE"
}
请注意,如果公寓AAA有多个预订,则所有预订文档都将添加到预订
公寓数组中。另外请注意,没有预订的公寓将不会有预订
阵列。接下来,我们将展开联接的bookings数组以摆脱该数组,并使用单个booking生成扁平的公寓对象(如果有):
接下来,我们按公寓名称进行过滤和分组过滤结果(因为一个公寓可以有多个不属于给定范围的预订)。最后一个阶段是投影。自3.2版以来,您可以使用运算符将两个集合外部连接起来:
db.apartment.aggregate([
{
$lookup: {
from: "booking",
localField: "_id",
foreignField: "apartmentID",
as: "booking"
}
},
{
$unwind: { path: "$booking", preserveNullAndEmptyArrays: true }
},
{
$match: {
$or: [
{ "booking": {$exists: false }},
{ "booking.checkin": {$gte: 1520000000} },
{ "booking.checkout": {$lte: 1510000000} }
]
}
},
{
$group: { _id: "$name" }
},
{
$project: { _id: 0, name: "$_id" }
}
])
输出:
{
"name" : "Apartment AAA"
},
{
"name" : "Apartment CCC"
},
{
"name" : "Apartment EEE"
}
详情: 第一阶段创建了公寓与预订的外部连接。此阶段产生的结果如下所示:
{
"_id": "AAA",
"name": "Apartment AAA",
"booking": [
{
"_id": 1,
"apartmentID": "AAA",
"checkin": 1490000000,
"checkout": 1499000000
},
{
"_id": 5,
"apartmentID": "AAA",
"checkin": 1500000000,
"checkout": 1590000000
},
]
}
...
{
"_id": "EEE",
"name": "Apartment EEE"
}
请注意,如果公寓AAA有多个预订,则所有预订文档都将添加到预订
公寓数组中。另外请注意,没有预订的公寓将不会有预订
阵列。接下来,我们将展开联接的bookings数组以摆脱该数组,并使用单个booking生成扁平的公寓对象(如果有):
接下来,我们按公寓名称进行过滤和分组过滤结果(因为一个公寓可以有多个不属于给定范围的预订)。最后一个阶段是投影。您可以使用
$not+$elemMatch
查找公寓预订是否有人
$elemMatch
查找是否有符合查询条件的已入住公寓,后跟$not
,在没有已入住的预订时返回公寓文档
差不多
db.apartment.aggregate({
$lookup: {
from: "booking",
localField: "_id",
foreignField: "apartmentID",
as: "bookings"
}
}, {
$match: {
"bookings": {
$not: {
$elemMatch: {
checkin: {
$lte: 1520000000
},
checkout: {
$gte: 1510000000
}
}
}
}
}
}, {
$project: {
_id: 0,
name: 1
}
})
您可以使用
$not+$elemMatch
查找公寓预订是否有人
$elemMatch
查找是否有符合查询条件的已入住公寓,后跟$not
,在没有已入住的预订时返回公寓文档
差不多
db.apartment.aggregate({
$lookup: {
from: "booking",
localField: "_id",
foreignField: "apartmentID",
as: "bookings"
}
}, {
$match: {
"bookings": {
$not: {
$elemMatch: {
checkin: {
$lte: 1520000000
},
checkout: {
$gte: 1510000000
}
}
}
}
}
}, {
$project: {
_id: 0,
name: 1
}
})
嗯,这个会给我与我需要的相反的东西(我需要没有人住的公寓),这会给我一个
ID
在name
中,而不是公寓。name
。最后,它也不包括公寓EEE,对不起,错过了这一部分。现在,aggregate只选择在给定范围内没有预订或没有预订的房间。这个房间将为我提供与我需要的相反的东西(我需要没有人住的公寓),这将在名称中为我提供ID
,而不是公寓。名称
。最后,它也不包括公寓EEE,对不起,错过了这一部分。现在“聚合”只选择在给定范围内没有预订或没有预订的房间。请再次单击-D我不知道$elemMatch的事。所以你阅读所有的公寓,然后进行预订查询,然后在预订后进行匹配。这很聪明,我没想过把数学往下推。其实很酷。问题:我想添加更多的$lookup以从其他表获取数据,我应该在$match之后这样做吗?是的,您可以在$match之后添加更多的阶段。这取决于你要做什么。基于这一点,你可能需要先放松,然后才能查找。酷酷的Veeram-我再次向你鞠躬哦,强大的Mongo大师:-)谢谢你的好话,但我根本不是大师。我很高兴在这个过程中学习和帮助他人。维拉姆再次出击!:-D我不知道$elemMatch的事。所以你阅读所有的公寓,然后进行预订查询,然后在预订后进行匹配。这很聪明,我没想过把数学往下推。其实很酷。问题:我想添加更多的$lookup以从其他表获取数据,我应该在$match之后这样做吗?是的,您可以在$match之后添加更多的阶段。这取决于你要做什么。基于这一点,你可能需要先放松,然后才能查找。酷酷的Veeram-我再次向你鞠躬哦,强大的Mongo大师:-)谢谢你的好话,但我根本不是大师。我很高兴在这个过程中学习和帮助他人。