失踪的孩子
在MongoDB中使用Mongoose,我的模式如下:
var PartSchema = new Schema({ partcode: String, children: [String] });
数据如下所示:
[{"partcode":"A1","children":["B1","B2","B3","B4"]}, {"partcode":"B1","children":["C11","C21","C31","C41"]}, {"partcode":"B3","children":["C13","C23","C33","C43"]},
我可以使用下面的静态调用来查询A1的子字段:
PartSchema.static('getChildren', function (partcode, callback) { var self = this; self.findOne({ partcode: partcode }, childrenOnly) .exec(function (err, doc) { return self.find({"partcode": {"$in": doc.children} }, exclId, callback); }); });
这返回(通过快递)
[{"partcode":"B1","children":["C11","C21","C31","C41"]}, {"partcode":"B3","children":["C13","C23","C33","C43"]}]
我需要的是返回所有未find的孩子,例如:
[{"children":["B2","B4"}]
您可以使用lodash库中的_.difference()
方法来计算数组集合差异:
var _ = require("lodash"); PartSchema.static('getChildren', function (partcode, callback) { var self = this; self.findOne({ partcode: partcode }, childrenOnly) .exec(function (err, doc) { var promise = self.find({"partcode": {"$in": doc.children} }, exclId).lean().exec(); promise.then(function (res){ var codes = res.map(function (m) { return m.children; }), obj = {"children": _.difference(doc.children, codes)}, result = []; result.push(obj); return result; }); }); });
– 更新 –
使用MongoDB的聚合框架 ,你可以达到预期的效果。 我们首先在mongoshell中演示这个。
假设您在零件集合中插入以下testing文档:
db.part.insert([ {"partcode":"A1","children":["B1","B2","B3","B4"]}, {"partcode":"B1","children":["C11","C21","C31","C41"]}, {"partcode":"B3","children":["C13","C23","C33","C43"]} ])
考虑到给定零件代码的子代码数组(例如"A1"
,它是["B1","B2","B3","B4"]
聚合可以用在这里。 在这种情况下,您的聚合pipe道将由以下聚合pipe道阶段组成:
-
$match
– 你需要这个过滤那些其子代码不在["B1","B2","B3","B4"]
数组中的文档。 这是使用$nin
操作符实现的。 -
$group
– 将来自上一个stream的所有文档分组,并创build具有父级代码的附加数组字段。 通过使用$addToSet
累加器运算符可能。 -
$project
– 通过添加一个新的字段部分partcode
(最终将成为结果对象的一部分)来重新partcode
stream中的每个文档,并抑制_id
字段。 在这里,您可以使用$setDifference
set操作符来获取标准中的父代码和不在stream水线文档中的父代码之间的数组差异。
你最后的聚合操作符看起来像这样(使用mongoshell):
var children = ["B1","B2","B3","B4"]; db.part.aggregate([ { "$match": { "children": { "$nin": children } } }, { "$group": { "_id": null, "parents": { "$addToSet": "$partcode" } } }, { "$project": { "_id": 0, "partcode": { "$setDifference": [ children, "$parents" ] } } } ]).pretty()
输出 :
/* 0 */ { "result" : [ { "partcode" : ["B2","B4"] } ], "ok" : 1 }
在Mongoose模式方法中使用相同的概念:
PartSchema.static('getChildren', function (partcode, callback) { var self = this; self.findOne({ partcode: partcode }, childrenOnly) .exec(function (err, doc) { var pipeline = [ { "$match": { "children": { "$nin": doc.children } } }, { "$group": { "_id": null, "parents": { "$addToSet": "$partcode" } } }, { "$project": { "_id": 0, "partcode": { "$setDifference": [ doc.children, "$parents" ] } } } ], self.aggregate(pipeline).exec(callback); }); });
或者使用Mongoose 聚合pipe道生成器进行stream畅的调用:
PartSchema.static('getMissedChildren', function (partcode, callback) { var self = this; self.findOne({ partcode: partcode }, childrenOnly) .exec(function (err, doc) { var promise = self.aggregate() .match({"children": { "$nin": doc.children }}) .group({"_id": null,"parents": {"$addToSet": "$partcode"}}) .project({"_id": 0,"partcode": {"$setDifference": [ doc.children, "$parents" ]}}) .exec(callback); }); });