如何使用$ 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
mobileNumber
和activities.name
,并且只有在activities.name
为true的情况下,我才不希望所有活动都是我想要的activities.name。
我可以得到varificationStatus
为true且activities.varificationStatus
为true的所有文档的列表,但是我不能仅从activities.name
select必需的字段( 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); } });
你实际上需要$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" }