在两个不同的字段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
值。
作为一个例子key
: michelangelo
为了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
– 这个阶段将把所有的school
和enrolledStudents
数组合并到一个组中的每个_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
用$project
replace上面聚合的最后两个阶段来格式化响应。
{$project: {"_id": 0 , id:"$_id", key:"$values.key", code:"$values.code"}}
示例响应
{ "_id" : 2, "key" : "michelangelo", "code" : 25 } { "_id" : 1, "key" : "michelangelo", "code" : "01" }
您可以使用$redact
而不是$group
& match
并使用$map
添加$project
来格式化响应。
$redact
一次通过文档级别,并根据匹配条件执行$$DESCEND
和$$PRUNE
。
唯一需要注意的是在id
的第一个文档级别使用$ifNull
,以便您可以$$DESCEND
embedded文档级别以便进一步处理。
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"}} ])