公寓表
{
"_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
}
我需要找到所有“name
”的“apartment
”,其中“1510000000
”与“1520000000
”之间没有预订
在这种情况下,结果应为:
{
"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
}
}
答案 0 :(得分:1)
从版本3.2开始,您可以使用$lookup运算符来外连接两个集合:
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有几个预订,所有预订文件将被添加到booking
公寓。另请注意,没有预订的公寓将不会有booking
阵列。接下来,我们展开联合预订数组以摆脱阵列并通过单次预订(如果有)生成扁平的公寓对象:
{
"_id": "AAA",
"name": "Apartment AAA",
"booking": {
"_id": 1,
"apartmentID": "AAA",
"checkin": 1490000000,
"checkout": 1499000000
}
},
{
"_id": "AAA",
"name": "Apartment AAA",
"booking": {
"_id": 5,
"apartmentID": "AAA",
"checkin": 1500000000,
"checkout": 1590000000
}
}
...
{
"_id": "EEE",
"name": "Apartment EEE"
}
接下来,我们按公寓名称对过滤结果进行过滤和分组(因为一个公寓可以有几个不属于给定范围的预订)。最后一个阶段 - 投射。
答案 1 :(得分: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
}
})