我有一个房间架构,如下所示:
let roomSchema = new mongoose.Schema({
events: [{type: mongoose.Schema.ObjectId, ref: 'Event'}],
name: { type: String, required: true, index: { unique: true } }
});
它包含一系列事件ID。 活动架构:
let eventSchema = new mongoose.Schema({
title: { type: String, required: true },
room: { type: mongoose.Schema.ObjectId, ref: 'Room', required: true },
date: { type: Date, required: true },
slot: { type: Number, required: true }
});
我想做的是:
"查询所有不包含特定日期和广告位"的活动的会议室。
因此,如果请求中的日期与房间和插槽的日期相匹配,那么该房间不应该在响应中。如果只有一个字段匹配,则应该在响应中。
我在这里发现了类似的问题,但我的情景没有:
https://stackoverflow.com/a/36371665/5115768
Mongoose query where value is not null
我尝试过类似的事情:
this.model.find(req.query).populate({
path: 'events',
match: {
date: { $ne: req.query.date },
slot: { $ne: req.query.slot }
}
}).exec((err, rooms) => {
rooms = rooms.filter((room) => {
return room.events != null;
});
res.status(200).json(rooms);
});
但当然它不起作用(房间总是空阵列)。我很难搞清楚这一点。
如何使用基于子文档(事件)的条件查询文档(会议室)?
我更改了架构和代码,以便slot
不再是数组。
如果我正确理解了@ Veeram的解决方案,就无法使用它,因为它会为"保留的房间"返回空的events
数组。这个问题是我需要用空events
数组过滤掉这些房间,其中包括首先没有任何关联事件的房间(这些房间不应该过滤掉) )。
现在我设法得到所有"保留的房间" (包含与req.query.date
和req.query.slot
匹配的事件的那些):
this.model.find(req.query).populate({
path: 'events',
match: {
$and: [
{ date: { $eq: date } },
{ slot: { $eq: slot } }
]
}
}).exec((err, reservedRooms) => {
reservedRooms = reservedRooms.filter(room => room.events.length > 0);
res.status(200).json(reservedRooms);
});
这与我想要的完全相反,但它是一个开始,我怎样才能反转"是什么?
答案 0 :(得分:0)
你试过了吗?
match: {
$not: [{
$and: [
date: { $eq: req.query.date },
slot: { $in: req.query.slot }
]
}]
}
答案 1 :(得分:0)
Populate为事件数组中的每个事件应用匹配条件。
因此,当对事件数组的每个元素应用否定时,在有可用事件(匹配)的数组与没有可用事件(不匹配)的数组之间,当获得填充数组时,区别就会丢失。
因此,您必须使用服务器$lookup
在整个阵列上应用条件。
以下聚合查询将过滤房间,其中事件(如果存在)不包含查询中给出的日期和插槽的文档。
使用$elemMatch
比较同一元素和$not
的查询条件,以返回没有数组元素包含查询条件的房间。
this.model.aggregate([
{
"$match":{"events":{"$exist":true}}
},
{
"$lookup": {
"from": "events", // Collection name not model or schema name
"localField": "events",
"foreignField": "_id",
"as": "events"
}
},
{
"$match":{"$not":{"$elemMatch":{"date": date, "slot":slot}}}
}
]).exec((err, reservedRooms) => {});
这将输出包含活动的房间。您可以使用排除的$project
从最终输出中删除事件。添加{$project:{"events":0}}
作为最后一个阶段。