如何使用 MongoDB 上的嵌套数据进行双重 $lookup 聚合?
How to make double $lookup aggregation with nested data on MongoDB?
我有 3 个模型:
- 学习
- 字集
- 类别
Study model引用了WordSet,然后WordSet引用了Category。
我了解到,为了正常显示数据,我使用填充。
但是在这种情况下,我需要一个包含很多 $lookup
.
的查询
如何从 WordSet 'populate' 类别中只显示重复次数最多的类别?
我会得到这样的回应:
"stats": [
{
"_id": null,
"numberOfStudies": 4,
"averageStudyTime": 82.5,
"allStudyTime": 330,
"longestStudy": 120,
"allLearnedWords": 8
"hardestCategory": "Work" // only this field is missing
}
]
我试过这样做:
const stats = await Study.aggregate([
{
// join User table
$lookup: {
from: 'User',
let: { userId: '$user' },
pipeline: [
{
$match: { $expr: { $eq: ['$_id', '$$userId'] } },
},
],
as: 'currentUser',
},
},
{
// join WordSet table
$lookup: {
from: 'WordSet',
let: { wordSetId: '$learnedWordSet' },
pipeline: [
{
$match: { $expr: { $eq: ['$_id', '$$wordSetId'] } },
},
{
// from this moment i'm not sure how to make it work
$lookup: {
from: 'Category',
let: { categoryId: '$category' },
pipeline: [
{
$match: { $expr: { $in: ['$_id', '$$categoryId'] } },
},
],
as: 'category',
},
},
],
as: 'wordSet',
},
},
{ // add wordset with category? this is not working
$addFields: {
wordSet: {
$arrayElemAt: ['$wordSet', 0],
},
},
},
{ // search by logged user
$match: { user: new ObjectID(currentUserId) },
},
{
$group: {
// display statistics about user's studying
_id: null,
numberOfStudies: { $sum: 1 },
averageStudyTime: { $avg: '$studyTime' },
allStudyTime: { $sum: '$studyTime' },
longestStudy: { $max: '$studyTime' },
allLearnedWords: { $sum: { $size: '$learnedWords' } },
// category: check which category is repeated the most and display it
},
},
]);
学习
const studySchema = new mongoose.Schema({
name: {
type: String,
},
studyTime: {
type: Number,
},
learnedWords: [String],
notLearnedWords: [String],
learnedWordSet: {
type: mongoose.Schema.Types.ObjectId,
ref: 'WordSet',
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
});
字集
const wordSetSchema = new mongoose.Schema({
name: {
type: String,
},
category: {
type: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
required: true,
},
],
},
});
类别
const categorySchema = new mongoose.Schema({
name: {
type: String,
},
});
不知道我理解的对不对,你可以试试查询,我已经改进了stages的使用,
$match
总是尝试在第一阶段使用阶段
$lookup
with User collection, there is no need to pipeline version, you can use localField and foreignField properties
I don't think is there any use of user document, and lookup stage because you want only statistics as per last $group
stage. so you can skip this lookup stage
- 在 WordSet 查找中,
$match
你的情况
$project
显示必填字段
$unwind
解构category
数组
$group
乘以category
得到总计数
$sort
按 count
降序排列
$limit
仅获取最常用的第一个和单个元素
$llokup
与 Category
集合
$project
显示必填字段,获取第一个类别名称
$group
阶段,hardestCategory
获取$first
类别名称
const stats = await Study.aggregate([
{ $match: { user: new ObjectID(currentUserId) } },
{
$lookup: {
from: "User",
localField: "user",
foreignField: "_id",
as: "currentUser"
}
},
{
$lookup: {
from: "WordSet",
let: { wordSetId: "$learnedWordSet" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$wordSetId"] } } },
{
$project: {
_id: 0,
category: 1
}
},
{ $unwind: "$category" },
{
$group: {
_id: "$category",
count: { $sum: 1 }
}
},
{ $sort: { count: -1 } },
{ $limit: 1 },
{
$lookup: {
from: "Category",
localField: "_id",
foreignField: "_id",
as: "category"
}
},
{
$project: {
_id: 0,
category: { $arrayElemAt: ["$category.name", 0] }
}
}
],
as: "wordSet"
}
},
{
$group: {
_id: null,
numberOfStudies: { $sum: 1 },
averageStudyTime: { $avg: "$studyTime" },
allStudyTime: { $sum: "$studyTime" },
longestStudy: { $max: "$studyTime" },
allLearnedWords: {
$sum: { $size: "$learnedWords" }
},
hardestCategory: {
$first: {
$first: "$wordSet.category"
}
}
}
}
])
我有 3 个模型:
- 学习
- 字集
- 类别
Study model引用了WordSet,然后WordSet引用了Category。
我了解到,为了正常显示数据,我使用填充。
但是在这种情况下,我需要一个包含很多 $lookup
.
如何从 WordSet 'populate' 类别中只显示重复次数最多的类别?
我会得到这样的回应:
"stats": [
{
"_id": null,
"numberOfStudies": 4,
"averageStudyTime": 82.5,
"allStudyTime": 330,
"longestStudy": 120,
"allLearnedWords": 8
"hardestCategory": "Work" // only this field is missing
}
]
我试过这样做:
const stats = await Study.aggregate([
{
// join User table
$lookup: {
from: 'User',
let: { userId: '$user' },
pipeline: [
{
$match: { $expr: { $eq: ['$_id', '$$userId'] } },
},
],
as: 'currentUser',
},
},
{
// join WordSet table
$lookup: {
from: 'WordSet',
let: { wordSetId: '$learnedWordSet' },
pipeline: [
{
$match: { $expr: { $eq: ['$_id', '$$wordSetId'] } },
},
{
// from this moment i'm not sure how to make it work
$lookup: {
from: 'Category',
let: { categoryId: '$category' },
pipeline: [
{
$match: { $expr: { $in: ['$_id', '$$categoryId'] } },
},
],
as: 'category',
},
},
],
as: 'wordSet',
},
},
{ // add wordset with category? this is not working
$addFields: {
wordSet: {
$arrayElemAt: ['$wordSet', 0],
},
},
},
{ // search by logged user
$match: { user: new ObjectID(currentUserId) },
},
{
$group: {
// display statistics about user's studying
_id: null,
numberOfStudies: { $sum: 1 },
averageStudyTime: { $avg: '$studyTime' },
allStudyTime: { $sum: '$studyTime' },
longestStudy: { $max: '$studyTime' },
allLearnedWords: { $sum: { $size: '$learnedWords' } },
// category: check which category is repeated the most and display it
},
},
]);
学习
const studySchema = new mongoose.Schema({
name: {
type: String,
},
studyTime: {
type: Number,
},
learnedWords: [String],
notLearnedWords: [String],
learnedWordSet: {
type: mongoose.Schema.Types.ObjectId,
ref: 'WordSet',
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
});
字集
const wordSetSchema = new mongoose.Schema({
name: {
type: String,
},
category: {
type: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
required: true,
},
],
},
});
类别
const categorySchema = new mongoose.Schema({
name: {
type: String,
},
});
不知道我理解的对不对,你可以试试查询,我已经改进了stages的使用,
$match
总是尝试在第一阶段使用阶段
$lookup
with User collection, there is no need to pipeline version, you can use localField and foreignField propertiesI don't think is there any use of user document, and lookup stage because you want only statistics as per last
$group
stage. so you can skip this lookup stage
- 在 WordSet 查找中,
$match
你的情况$project
显示必填字段$unwind
解构category
数组$group
乘以category
得到总计数$sort
按count
降序排列$limit
仅获取最常用的第一个和单个元素$llokup
与Category
集合$project
显示必填字段,获取第一个类别名称
$group
阶段,hardestCategory
获取$first
类别名称
const stats = await Study.aggregate([
{ $match: { user: new ObjectID(currentUserId) } },
{
$lookup: {
from: "User",
localField: "user",
foreignField: "_id",
as: "currentUser"
}
},
{
$lookup: {
from: "WordSet",
let: { wordSetId: "$learnedWordSet" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$wordSetId"] } } },
{
$project: {
_id: 0,
category: 1
}
},
{ $unwind: "$category" },
{
$group: {
_id: "$category",
count: { $sum: 1 }
}
},
{ $sort: { count: -1 } },
{ $limit: 1 },
{
$lookup: {
from: "Category",
localField: "_id",
foreignField: "_id",
as: "category"
}
},
{
$project: {
_id: 0,
category: { $arrayElemAt: ["$category.name", 0] }
}
}
],
as: "wordSet"
}
},
{
$group: {
_id: null,
numberOfStudies: { $sum: 1 },
averageStudyTime: { $avg: "$studyTime" },
allStudyTime: { $sum: "$studyTime" },
longestStudy: { $max: "$studyTime" },
allLearnedWords: {
$sum: { $size: "$learnedWords" }
},
hardestCategory: {
$first: {
$first: "$wordSet.category"
}
}
}
}
])