失踪的孩子

在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道阶段组成:

  1. $match – 你需要这个过滤那些其子代码不在["B1","B2","B3","B4"]数组中的文档。 这是使用$nin操作符实现的。

  2. $group – 将来自上一个stream的所有文档分组,并创build具有父级代码的附加数组字段。 通过使用$addToSet累加器运算符可能。

  3. $project – 通过添加一个新的字段部分partcode (最终将成为结果对象的一部分)来重新partcodestream中的每个文档,并抑制_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); }); });