如何使用$ filter(聚合)来select一些数组的字段只有条件为真?

在这里,我会告诉你我到底想要什么。 假设我有以下两个文件为XYZ模型。

[ { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "email" : "one@one.com", "mobileNumber" : "910123456989", "verificationStatus" : true, "activities" : [ { "name" : "a1", "_id" : ObjectId("59ef8786e8c7d60552139bae"), "type" : 0, "level" : null, "verificationStatus" : true }, { "name" : "a2", "_id" : ObjectId("59ef8786e8c7d60552139bad"), "type" : 0, "level" : null, "verificationStatus" : false } ], "address" : { "line1" : "asd", "line2" : "asd", "city" : "sd", "state" : "sd", "country" : "asd", "landmark" : "sdsa", "pincode" : "560090" }, "__v" : 0 }, { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "email" : "one@one.com", "mobileNumber" : "919876543210", "verificationStatus" : true, "activities" : [ { "name" : "b1", "_id" : ObjectId("59ef8786e8c7d60552139bae"), "level" : null, "type" : 0, "verificationStatus" : true }, { "name" : "b2", "_id" : ObjectId("59ef8786e8c7d60552139bad"), "level" : null, "type" : 0, "verificationStatus" : false } ], "address" : { "line1" : "asd", "line2" : "asd", "city" : "sd", "state" : "sd", "country" : "asd", "landmark" : "sdsa", "pincode" : "560090" }, "__v" : 0 } ] 

现在,我只想从verificationStatus为true的文档中获取name mobileNumberactivities.name ,并且只有在activities.name为true的情况下,我才不希望所有活动都是我想要的activities.name。

我可以得到varificationStatus为true且activities.varificationStatus为true的所有文档的列表,但是我不能仅从activities.nameselect必需的字段( activities.name )。

我目前的代码是:

 XYZ.aggregate( [ { $match: { verificationStatus: true } }, { $project: { name: 1, coverImage: 1, location: 1, address: 1, dist: 1, activities: { $filter: { input: "$activities", as: "activity", cond: { $eq: ["$$activity.verificationStatus", true] } } } } }], function (err, list) { if (err) { reject(err); } else { resolve(list); } }); 

       

网上收集的解决方案 "如何使用$ filter(聚合)来select一些数组的字段只有条件为真?"

你实际上需要$map来“修改”返回的数组元素,因为$filter只是“select”“匹配”的数组元素:

 XYZ.aggregate( [ { $match: { verificationStatus: true } }, { $project: { name: 1, mobileNumber: 1, activities: { $map: { input: { $filter: { input: "$activities", as: "activity", cond: "$$activity.verificationStatus" } }, "as": "a", "in": "$$a.name" } } } }], function (err, list) { ... 

会返回:

 { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "910123456989", "activities" : ["a1"] } { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "919876543210", "activities" : ["b1"] } 

还要注意$filter中的"cond"可以缩短,因为它已经是一个boolean值。

如果您只想要"name"属性的“对象”,那么只返回该分配的键:

 XYZ.aggregate( [ { $match: { verificationStatus: true } }, { $project: { name: 1, mobileNumber: 1, activities: { $map: { input: { $filter: { input: "$activities", as: "activity", cond: "$$activity.verificationStatus" } }, "as": "a", "in": { "name": "$$a.name" } } } } }], function (err, list) { ... 

返回为:

 { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "910123456989", "activities" : [{ "name": "a1" }] } { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "919876543210", "activities" : [{ "name": "b1" }] } 

如果您确实知道您在数组中匹配“one”元素,则可以使用带有$arrayElemAt $indexOfArray ,如果您有MongoDB 3.4

 { "$project": { "name": 1, "mobileNumber": 1, "activities": { "$arrayElemAt": [ "$activities.name", { "$indexOfArray": [ "$activities.verificationStatus", true ] } ] } }} 

由于这是一个奇异的值,而不是一个数组,所以会出现一点点不同:

 { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "910123456989", "activities" : "a1" } { "_id" : ObjectId("59ef8786e8c7d60552139ba9"), "name" : "s1", "mobileNumber" : "919876543210", "activities" : "b1" }