在两个不同的字段mongodb + node.js中search值

我是新手。 但我试图学习编写查询的最合理的方法。

假设我有collections这是;

{ "id" : NumberInt(1), "school" : [ { "name" : "george", "code" : "01" }, { "name" : "michelangelo", "code" : "01" } ], "enrolledStudents" : [ { "userName" : "elisabeth", "code" : NumberInt(21) } ] } { "id" : NumberInt(2), "school" : [ { "name" : "leonarda da vinci", "code" : "01" } ], "enrolledStudents" : [ { "userName" : "michelangelo", "code" : NumberInt(25) } ] } 

我想列出一个key与他们相应的code值。

作为一个例子keymichelangelo

为了find密钥的出现,我写了两个不同的aggregation查询:

 db.test.aggregate([ {$unwind: "$school"}, {$match : {"school.name" : "michelangelo"}}, {$project: {_id: "$id", "key" : "$school.name", "code" : "$school.code"}} ]) 

 db.test.aggregate([ {$unwind: "$enrolledStudents"}, {$match : {"enrolledStudents.userName" : "michelangelo"}}, {$project: {_id: "$id", "key" : "$enrolledStudents.userName", "code" : "$enrolledStudents.code"}} ]) 

这两个查询的结果返回我想要的;

 { "_id" : 1, "key" : "michelangelo", "code" : "01" } { "_id" : 2, "key" : "michelangelo", "code" : 25 } 

其中之一是在enrolledStudents的学生中search,另一个是在school领域search。

这两个查询可以减less到更多的逻辑查询吗? 或者这是唯一的方法吗?

PS:我知道数据库结构是不合逻辑的,但我试图模拟。

编辑我尝试用find来编写查询。

 db.test.find({$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}).pretty() 

但是这将整个文档返回为;

 { "id" : 1, "school" : [ { "name" : "george", "code" : "01" }, { "name" : "michelangelo", "code" : "01" } ], "enrolledStudents" : [ { "userName" : "elisabeth", "code" : 21 } ] } { "id" : 2, "school" : [ { "name" : "leonarda da vinci", "code" : "01" } ], "enrolledStudents" : [ { "userName" : "michelangelo", "code" : 25 } ] } 

Mongo 3.4

$match – 这个阶段将保留所有的school数组和enrolledStudents ,其中至less有一个embedded式文档与查询条件

$group – 这个阶段将把所有的schoolenrolledStudents数组合并到一个组中的每个_id 2d数组中。

$project – 这个阶段将$filter符合查询条件的merge数组,并$map将数组$map到新的标签values数组。

$unwind – 这个阶段将使数组扁平化。

$addFields$replaceRoot – 这个阶段将添加id字段并将values数组提升到顶部。

 db.collection.aggregate([ {$match : {$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}}, {$group: {_id: "$id", merge : {$push:{$setUnion:["$school", "$enrolledStudents"]}}}}, {$project: { values: { $map: { input: { $filter: { input: {"$arrayElemAt":["$merge",0]}, as: "onef", cond: { $or: [{ $eq: ["$$onef.userName", "michelangelo"] }, { $eq: ["$$onef.name", "michelangelo"] }] } } }, as: "onem", in: { key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] }, code : "$$onem.code"} } } } }, {$unwind: "$values"}, {$addFields:{"values.id":"$_id"}}, {$replaceRoot: { newRoot:"$values"}} ]) 

示例响应

 { "_id" : 2, "key" : "michelangelo", "code" : 25 } { "_id" : 1, "key" : "michelangelo", "code" : "01" } 

Mongo <= 3.2

$projectreplace上面聚合的最后两个阶段来格式化响应。

 {$project: {"_id": 0 , id:"$_id", key:"$values.key", code:"$values.code"}} 

示例响应

 { "_id" : 2, "key" : "michelangelo", "code" : 25 } { "_id" : 1, "key" : "michelangelo", "code" : "01" } 

您可以使用$redact而不是$groupmatch并使用$map添加$project来格式化响应。

$redact一次通过文档级别,并根据匹配条件执行$$DESCEND$$PRUNE

唯一需要注意的是在id的第一个文档级别使用$ifNull ,以便您可以$$DESCENDembedded文档级别以便进一步处理。

 db.collection.aggregate([ { $redact: { $cond: [{ $or: [{ $eq: ["$userName", "michelangelo"] }, { $eq: ["$name", "michelangelo"] }, { $ifNull: ["$id", false] }] }, "$$DESCEND", "$$PRUNE"] } }, { $project: { id:1, values: { $map: { input: {$setUnion:["$school", "$enrolledStudents"]}, as: "onem", in: { key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] }, code : "$$onem.code"} } } } }, {$unwind: "$values"}, {$project: {_id:0,id:"$id", key:"$values.key", code:"$values.code"}} ])