过滤数组时如何包含空数组

时间:2017-09-20 03:00:22

标签: node.js mongodb mongoose mongodb-query aggregation-framework

这是我的项目模型。

const itemSchema = new Schema({
  name: String,
  category: String,
  occupied: [Number],
  active: { type: Boolean, default: true },
});

我想过滤掉“被占用的”#39;阵列。因此,我使用聚合和放松占用'字段。

所以我应用匹配查询。并按_id分组。 但是,如果过滤了“被占用”的话。数组为空,项目消失。

这是我的代码

Item.aggregate([
  { $match: {
    active: true
  }},
  { $unwind:
    "$occupied",
  },
  { $match: { $and: [
    { occupied: { $gte: 100 }},
    { occupied: { $lt: 200 }}
  ]}},
  { $group : {
    _id: "$_id",
    name: { $first: "$name"},
    category: { $first: "$category"},
    occupied: { $addToSet : "$occupied" }
  }}
], (err, items) => {
  if (err) throw err;
  return res.json({ data: items });
}); 

以下是示例数据集

{ 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"),
    "name" : "printer1",
    "category" : "printer",
    "occupied" : [ 95, 100, 145, 200 ],
    "active" : true
},
{
  "_id" : ObjectId("59c2dbed992fb91b7421b1ad"),
   "name" : "printer2",
   "category" : "printer",
   "occupied" : [ ],
   "active" : true
}

以上查询结果

[
  { 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"),
    "name" : "printer1",
    "category" : "printer",
    "occupied" : [ 100, 145 ],
    "active" : true
  }
]

和我想要的结果

[
  { 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"),
    "name" : "printer1",
    "category" : "printer",
    "occupied" : [ 100, 145 ],
    "active" : true
  },
  { 
    "_id" : ObjectId("59c2dbed992fb91b7421b1ad"),
    "name" : "printer2",
    "category" : "printer",
    "occupied" : [ ],
    "active" : true
  }
]

我怎么能这样做?

提前致谢。

1 个答案:

答案 0 :(得分:0)

在最简单的形式中,您只需首先不使用$unwind即可。您的条件意味着您正在寻找"独特的套装"匹配到特定值。

为此,您使用$filter和"设置运算符"像$setUnion一样将输入值减少到" set"首先:

Item.aggregate([
  { "$match": { "active": true } },
  { "$project": {
    "name": 1,
    "category": 1,
    "occupied": { 
      "$filter": {
        "input": { "$setUnion": [ "$occupied", []] },
        "as": "o",
        "cond": {
          "$and": [
            { "$gte": ["$$o", 100 ] },
            { "$lt": ["$$o", 200] }
          ]
        }
      }
    }
  }}
], (err, items) => {
  if (err) throw err;
  return res.json({ data: items });
});

自MongoDB v3以来,两者都存在,所以以这种方式做事情是很常见的做法。

如果由于某种原因您仍在使用MongoDB 2.6,那么您可以应用$map$setDifference代替:

Item.aggregate([
  { "$match": { "active": true } },
  { "$project": {
    "name": 1,
    "category": 1,
    "occupied": { 
      "$setDifference": [
        { "$map": {
          "input": "$occupied",
          "as": "o",
          "in": {
            "$cond": {
              "if": {
                "$and": [
                  { "$gte": ["$$o", 100 ] },
                  { "$lt": ["$$o", 200] }
                ]
              },
              "then": "$$o",
              "else": false
            }
          }
        }},
        [false]
      ]
    }
  }}
], (err, items) => {
  if (err) throw err;
  return res.json({ data: items });
});

它是相同的"独特的集合"将数组拉开,过滤项目并将其与$addToSet一起重新组合。不同之处在于它的效率更高,并且保留(或生成)一个没有任何问题的空数组。