我有3个班级:父母-中级-子女。所有关系均为“ 1:m”。 任务是:为每个父母获得有条件的所有孩子的总和。
代码如下:
'use strict';
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let TestParentSchema = new Schema({
Name: { type: String },
});
module.exports = mongoose.model('TestParent', TestParentSchema);
'use strict';
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let TestIntermediateSchema = new Schema({
Name: { type: String },
Parent: { type: Schema.ObjectId, ref: 'TestParent' },
});
module.exports = mongoose.model('TestIntermediate', TestIntermediateSchema);
'use strict';
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let TestChildSchema = new Schema({
Name: { type: String },
Value: { type: Number, required: true },
Intermediate: { type: Schema.ObjectId, ref: 'TestIntermediate' },
});
module.exports = mongoose.model('TestChild', TestChildSchema);
按如下所示填充它:
let parent1 = new TestParent({ Name: 'parent1' });
let parent2 = new TestParent({ Name: 'parent2' });
parent1.save();
parent2.save();
let inter11 = new TestIntermediate({ Name: 'inter1-1', Parent: parent1 });
let inter21 = new TestIntermediate({ Name: 'inter2-1', Parent: parent2 });
inter11.save();
inter21.save();
let child111 = new TestChild({ Name: 'child1-1-1', Intermediate: inter11, Value: 5 });
let child112 = new TestChild({ Name: 'child1-1-2', Intermediate: inter11, Value: 60 });
let child211 = new TestChild({ Name: 'child2-1-1', Intermediate: inter21, Value: 10 });
let child212 = new TestChild({ Name: 'child2-1-2', Intermediate: inter21, Value: 70 });
child111.save();
child112.save();
child211.save();
child212.save();
目标是为每个父母的Value <50的孩子求和。 (“ parent1”为“ 5”,“ parent2”为“ 10”)
首先,让我们获取所有子代的值:
TestParent.aggregate(
[
{
$lookup: {
from: 'testintermediates',
localField: '_id',
foreignField: 'Parent',
as: 'myIntermediates',
},
},
{
$lookup: {
from: 'testchildren',
localField: 'myIntermediates._id',
foreignField: 'Intermediate',
as: 'myChildren',
},
},
{
$project: {
myName: '$Name',
sumChildren: { $sum: '$myChildren.Value' },
},
},
],
function(err, results) {
let res1 = results[0].sumChildren === 5;
let res2 = results[1].sumChildren === 10;
}
);
好的。
现在让我们尝试向第二次查找添加条件:
TestParent.aggregate(
[
{
$lookup: {
from: 'testintermediates',
localField: '_id',
foreignField: 'Parent',
as: 'myIntermediates',
},
},
// {
// $lookup: {
// from: 'testchildren',
// localField: 'myIntermediates._id',
// foreignField: 'Intermediate',
// as: 'myChildren',
// },
// },
// { //to check if this approach works with the first level (it works)
// $lookup: {
// from: 'testintermediates',
// let: { myid: '$_id' },
// pipeline: [
// {
// $match:
// {
// $expr: {
// $eq: ['$Parent', '$$myid'],
// // $eq: ['$LocalId', 55],
// },
// },
// },
// ],
// as: 'myIntermediates',
// },
// },
{
$lookup: {
from: 'testchildren',
let: { intermedId: '$myIntermediates._id' },
pipeline: [
{
$match:
{
$expr: {
$eq: ['$Intermediate', '$$intermedId'], //it doesn't work (
// $eq: ['$Value', 60], //it works
},
},
},
],
as: 'myChildren',
},
},
{
$project: {
myName: '$Name',
sumChildren: { $sum: '$myChildren.Value' },
},
},
],
function(err, results) {
let res1 = results[0].sumChildren === 5;
let res2 = results[1].sumChildren === 10;
}
);
就目前而言,我通过将'$ unwind'与'$ group'结合使用来解决此任务,但想知道是否有一种方法可以仅向管道添加条件。谢谢您的帮助。
答案 0 :(得分:0)
想知道是否有一种方法可以向管道中添加条件
首先,让我们从管道的第一阶段开始进行分解。 $lookup
的第一阶段:
"$lookup": {
from: "testintermediates",
localField: "_id",
foreignField: "Parent",
as: "myIntermediates"}
将匹配的中间体数组返回为myIntermediates
。例如:
{"_id": 1,
"x": "some value",
"myIntermediates": [
{ "_id": 1, "Parent": 1, "y": 5 },
{ "_id": 2, "Parent": 1, "y": 7 },
{ "_id": 3, "Parent": 1, "y": 2 }
]}
当您使用另一个single equality match syntax of $lookup链接第二个$lookup
阶段时:
"$lookup": {
from: "testchildren",
localField: "myIntermediates._id",
foreignField: "Intermediate",
as: "myChildren"}
之所以可行,是因为当localField
是一个数组时,localField
和foreignField
之间的相等条件被视为:
"foreignField": { "$in": [ "localField.elem1", "localField.elem2", ... ] }
因此,如果您在$in expression的第二个$lookup
阶段也使用uncorrelated subqueries $lookup syntax,它也应该工作。
使用$eq
无效的原因是,单个值与值数组之间的相等比较不正确。
总而言之,您的聚合查询可以写为:
TestParent.aggregate(
[
{"$lookup": {
from: "testintermediates",
localField: "_id",
foreignField: "Parent",
as: "myIntermediates",
},
},
{"$lookup": {
from: "testchildren",
let: { "intermedId": "$myIntermediates._id" },
pipeline: [
{"$match":
{"$expr": {
"$in": ["$Intermediate", "$$intermedId"],
},
},
},
],
as: "myChildren",
},
},
{"$project": {
myName: "$Name",
sumChildren: { "$sum": "$myChildren.Value" },
},
},
]);