Mongo db - 如何使用分页连接和排序两个集合
Mongo db - how to join and sort two collection with pagination
我有 2 个合集:
- 办公室-
{
_id: ObjectId(someOfficeId),
name: "some name",
..other fields
}
- 文件-
{
_id: ObjectId(SomeId),
name: "Some document name",
officeId: ObjectId(someOfficeId),
...etc
}
我需要获取按涉及办公室的文档数排序的办公室列表。还要实现分页。
我尝试通过聚合和使用 $lookup
来做到这一点
const aggregation = [
{
$lookup: {
from: 'documents',
let: {
id: '$id'
},
pipeline: [
{
$match: {
$expr: {
$eq: ['$officeId', '$id']
},
// sent_at: {
// $gte: start,
// $lt: end,
// },
}
}
],
as: 'documents'
},
},
{ $sortByCount: "$documents" },
{ $skip: (page - 1) * limit },
{ $limit: limit },
];
但这对我不起作用
任何想法如何实现这个?
p.s。我需要显示包含 0 个文件的办公室,所以通过 documets 获取办公室 - 对我不起作用
查询
- 您可以使用 lookup 加入该字段,并通过管道进行分组,这样您就可以计算每个办公室的文档(而不是将文档放入数组中,因为您只计算计数)
$set
是在顶级字段中获取该计数
- 使用
noffices
字段排序
- 你可以使用skip/limit的方式进行分页,但是如果你的collection很大,它会很慢见this。或者,您可以使用
_id
自然顺序进行分页,或者在每个查询中检索更多文档并将它们保存在内存中(而不是只检索一页的文档)
offices.aggregate(
[{"$lookup":
{"from":"documents",
"localField":"_id",
"foreignField":"officeId",
"pipeline":[{"$group":{"_id":null, "count":{"$sum":1}}}],
"as":"noffices"}},
{"$set":
{"noffices":
{"$cond":
[{"$eq":["$noffices", []]}, 0,
{"$arrayElemAt":["$noffices.count", 0]}]}}},
{"$sort":{"noffices":-1}}])
正如另一个答案所指出的,您忘记了 id
的 _
,但您不需要 let
或在管道内与 $expr
匹配,通过上面的查找。另外 $sortByCount
不计算数组的成员,您需要 $size
(按计数排序只是分组,而不是对数组进行计数)。但是你不需要 $size
你也可以像上面那样在管道中计算它们。
编辑
查询
- 您可以在管道中添加您需要的内容或直接删除它
- 这会保留所有文档,并计算数组大小
- 然后排序
offices.aggregate(
[{"$lookup":
{"from":"documents",
"localField":"_id",
"foreignField":"officeId",
"pipeline":[],
"as":"alldocuments"}},
{"$set":{"ndocuments":{"$size":"$alldocuments"}}},
{"$sort":{"ndocuments":-1}}])
您的查询有两个错误
同时使用 $let
传递变量。您忘记了 $_id
本地字段
的 _
let: {
id: '$id'
},
在 $exp
中,因为您使用的是变量 id
而不是
Documents
集合,你应该使用 $$
来引用变量。
$expr: {
$eq: ['$officeId', '$$id']
},
我有 2 个合集:
- 办公室-
{
_id: ObjectId(someOfficeId),
name: "some name",
..other fields
}
- 文件-
{
_id: ObjectId(SomeId),
name: "Some document name",
officeId: ObjectId(someOfficeId),
...etc
}
我需要获取按涉及办公室的文档数排序的办公室列表。还要实现分页。
我尝试通过聚合和使用 $lookup
来做到这一点const aggregation = [
{
$lookup: {
from: 'documents',
let: {
id: '$id'
},
pipeline: [
{
$match: {
$expr: {
$eq: ['$officeId', '$id']
},
// sent_at: {
// $gte: start,
// $lt: end,
// },
}
}
],
as: 'documents'
},
},
{ $sortByCount: "$documents" },
{ $skip: (page - 1) * limit },
{ $limit: limit },
];
但这对我不起作用
任何想法如何实现这个?
p.s。我需要显示包含 0 个文件的办公室,所以通过 documets 获取办公室 - 对我不起作用
查询
- 您可以使用 lookup 加入该字段,并通过管道进行分组,这样您就可以计算每个办公室的文档(而不是将文档放入数组中,因为您只计算计数)
$set
是在顶级字段中获取该计数- 使用
noffices
字段排序 - 你可以使用skip/limit的方式进行分页,但是如果你的collection很大,它会很慢见this。或者,您可以使用
_id
自然顺序进行分页,或者在每个查询中检索更多文档并将它们保存在内存中(而不是只检索一页的文档)
offices.aggregate(
[{"$lookup":
{"from":"documents",
"localField":"_id",
"foreignField":"officeId",
"pipeline":[{"$group":{"_id":null, "count":{"$sum":1}}}],
"as":"noffices"}},
{"$set":
{"noffices":
{"$cond":
[{"$eq":["$noffices", []]}, 0,
{"$arrayElemAt":["$noffices.count", 0]}]}}},
{"$sort":{"noffices":-1}}])
正如另一个答案所指出的,您忘记了 id
的 _
,但您不需要 let
或在管道内与 $expr
匹配,通过上面的查找。另外 $sortByCount
不计算数组的成员,您需要 $size
(按计数排序只是分组,而不是对数组进行计数)。但是你不需要 $size
你也可以像上面那样在管道中计算它们。
编辑
查询
- 您可以在管道中添加您需要的内容或直接删除它
- 这会保留所有文档,并计算数组大小
- 然后排序
offices.aggregate(
[{"$lookup":
{"from":"documents",
"localField":"_id",
"foreignField":"officeId",
"pipeline":[],
"as":"alldocuments"}},
{"$set":{"ndocuments":{"$size":"$alldocuments"}}},
{"$sort":{"ndocuments":-1}}])
您的查询有两个错误
同时使用 $let
传递变量。您忘记了 $_id
本地字段
_
let: {
id: '$id'
},
在 $exp
中,因为您使用的是变量 id
而不是
Documents
集合,你应该使用 $$
来引用变量。
$expr: {
$eq: ['$officeId', '$$id']
},