NodeJS 如何展开子文档数组,然后反转过程,而不丢失其他键?

vojdkbi0  于 11个月前  发布在  Node.js
关注(0)|答案(1)|浏览(91)

我对 Mongoose 完全陌生。
我有这样的Schema:

const houseSchema = new mongoose.Schema({  
  _id: String,
  housename:  {type: String,unique: true},
  adress: String,
  people: [ {
      name: String,
      age: Number
    } ],
});

字符串
并记录:

let house = new House({
    _id: 20,
    housename: "white",
    adress: "St1",
    people:[
      {name: "Jon", age: 23},
      {name: "Ann", age:50},
      {name: "Pat", age:20},
      {name: "Helen", age:15}]
  });


我想通过id找到这个文档,并通过年龄过滤people数组,然后返回没有过滤对象的完整文档。因此预期输出将是:(对于年龄>21):

{
    _id: 20,
    housename: "white",
    adress: "St1",
    people:[
      {_id:"65976faeaa644d02c4090826", name: "Jon", age: 23},
      {_id:"65976faeaa644d02c4090827", name: "Ann", age:50}
    ]
 }


经过几个小时的尝试,我对这个问题的解决方案是:

app.get("/api/test", (req, res) => {
  var searchID = "20";
  var minAge = 21;
  House.aggregate([{$match: {_id: searchID}}])
  .unwind("people").match({'people.age': {$gt: minAge}})
  .group({    
        _id: "$_id",       
        people: {$push: "$people"}         
  }) 
  .exec((err,data)=>{
        res.json(data); 
    }); 
});


所以首先我匹配id,然后倒带people数组-这样我就可以过滤掉它,然后我尝试重新加入到第一个表单。**然而,分组后我丢失了 housenameadress 字段。**这里是输出:

{"_id":"20",
"people":[
{"_id":"65976faeaa644d02c4090826","name":"Jon","age":23},{"_id":"65976faeaa644d02c4090827","name":"Ann","age":50}]}


我不知道如何在输出中保留 housenameadress 字段。我试过添加.projection({housename:1,adress:1...});,但它什么也没做,我认为这些键在group()之后的管道中不存在。我也一直在考虑将这些值保存到match()之后的vars中,然后在末尾添加它们,但我不知道如何在链的中间访问它们。

wmtdaxz3

wmtdaxz31#

你可以使用一个简单的$filter来过滤符合过滤条件的people对象,如下所示:

app.get("/api/test", async (req, res) => { //< Mark as async
  var searchID = "20";
  var minAge = 21;
  try{
      const data = await House.aggregate([
      {
         $match: {
            "_id": searchID 
         }
      },
      {
         "$addFields": {
            people: {
               $filter: {
                  input: "$people",
                  as: "p",
                  cond: {
                     $gt: [
                        "$$p.age",
                        minAge 
                     ]
                  }
               }
            }
         }
      }
      ]);
      res.json(data);
   } catch(err){
      console.log(err);
      res.json({message: 'Error on server'});
   }
});

字符串
请参阅HERE以获取工作示例。
$addFields的使用在这里很重要,因为:
向文档添加新字段。$addFields输出包含输入文档中所有现有字段和新添加字段的文档。$addFields stage等效于$project stage,它显式指定输入文档中所有现有字段并添加新字段。
我想这就是你在使用$project时遇到麻烦的地方。我所做的就是使用$addFields用新的过滤版本覆盖现有的people属性。

相关问题