缺少 Children
Missing Children
将 Mongoose 与 MongoDB 结合使用,我的 Schema 如下:
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 的 children 字段:
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);
});
});
这 return 秒(通过快递)
[{"partcode":"B1","children":["C11","C21","C31","C41"]},
{"partcode":"B3","children":["C13","C23","C33","C43"]}]
我需要的是return全部children没有找到,例如:
[{"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的aggregation framework就可以达到想要的效果。让我们先在 mongoshell 中演示一下。
假设您在部件集合中插入以下测试文档:
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"]
。在这种情况下,您的聚合管道将包含以下聚合管道阶段:
$match
- You need this to filter those documents whose children partcodes are not in the ["B1","B2","B3","B4"]
array. This is achieved using the $nin
运算符.
$group
- This groups all the documents from the previous stream and creates an additional array field that has the parent partcodes. Made possible by using the $addToSet
累加器运算符。
$project
- Reshapes each document in the stream by adding a new field partcode
(which will eventually become part of the result object) and suppresses the _id
field. This is where you can get the array difference between the parent partcode in the criteria and those not in the pipeline documents, made possible using the $setDifference
设置运算符.
您最终的聚合运算符将如下所示(使用 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 aggregation pipeline builder 进行流畅的调用:
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);
});
});
将 Mongoose 与 MongoDB 结合使用,我的 Schema 如下:
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 的 children 字段:
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);
});
});
这 return 秒(通过快递)
[{"partcode":"B1","children":["C11","C21","C31","C41"]},
{"partcode":"B3","children":["C13","C23","C33","C43"]}]
我需要的是return全部children没有找到,例如:
[{"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的aggregation framework就可以达到想要的效果。让我们先在 mongoshell 中演示一下。
假设您在部件集合中插入以下测试文档:
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"]
。在这种情况下,您的聚合管道将包含以下聚合管道阶段:
$match
- You need this to filter those documents whose children partcodes are not in the["B1","B2","B3","B4"]
array. This is achieved using the$nin
运算符.$group
- This groups all the documents from the previous stream and creates an additional array field that has the parent partcodes. Made possible by using the$addToSet
累加器运算符。$project
- Reshapes each document in the stream by adding a new fieldpartcode
(which will eventually become part of the result object) and suppresses the_id
field. This is where you can get the array difference between the parent partcode in the criteria and those not in the pipeline documents, made possible using the$setDifference
设置运算符.
您最终的聚合运算符将如下所示(使用 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 aggregation pipeline builder 进行流畅的调用:
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);
});
});