查询具有基于子文档

时间:2017-12-25 15:29:46

标签: javascript node.js mongodb mongoose mongodb-query

我有一个房间架构,如下所示:

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.datereq.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);
});

这与我想要的完全相反,但它是一个开始,我怎样才能反转"是什么?

2 个答案:

答案 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}}作为最后一个阶段。