优化 mongoDB 查询以从单独的集合中获取项目数
Optimize mongoDB query to get count of items from separate collection
我有两个集合,即“标签”和“书签”。
Tags documents:
{
"taggedBookmarksCount": 2,
"taggedNotesCount": 0,
"_id": "627a80e6b12b0dc78b3a6d4b",
"name": "Article"
},
{
"taggedBookmarksCount": 0,
"taggedNotesCount": 0,
"_id": "62797885b479b5906ef6ed43",
"name": "Client"
},
Bookmark Documents:
{
"_id": "627a814db12b0dc78b3a6d54",
"bookmarkTags": [
{
"tagId": "627a814db12b0dc78b3a6d55",
"tag": "Article"
},
{
"tagId": "627a814db12b0dc78b3a6d56",
"tag": "to be read"
}
],
"bookmarkTitle": "Please sorrow of work",
}
Objective是获取“标签”集合中所有标签的书签数。
下面是我当前的实现,returns 每个 tags.But 这个查询的书签计数需要大约 3 秒到 运行(REST API 响应时间) 20 个标签。
tags = await Tag.find(
{
userId: req.params.userId
},
{ _id: 1 }
);
tagIds = tags.map(tag => {
return tag._id.toString();
});
const tagCounts = await Promise.all(
tagIds.map(async tagId => {
const count = await Model.aggregate([
{
$match: {
bookmarkTags: {
$elemMatch: {
tagId: tagId
}
}
}
},
{
$group: {
_id: '_id',
count: {
$sum: 1
}
}
}
]);
return { tagId, count: count[0] ? count[0].count : 0 };
})
);
我假设它需要更长的时间,因为我正在映射所有标签,有多次往返 database.Please 建议减少查询执行时间的方法。
您可以按以下方式进行
db.bookmark.aggregate([
{
"$unwind": "$bookmarkTags" //Reshape tags
},
{
"$lookup": { //Do a join
"from": "tags",
"localField": "bookmarkTags.tagId",
"foreignField": "_id",
"as": "btags"
}
},
{
"$unwind": { //reshape the array elements
path: "$btags",
preserveNullAndEmptyArrays: true
}
},
{
"$group": { // Group tag wise bookmarks
"_id": "$bookmarkTags.tagId",
"docs": {
"$addToSet": "$btags"
}
}
},
{
"$project": { //Get counts, project what you want.
tag_id: "$_id",
"count": {
"$size": "$docs"
},
_id: 0
}
}
])
如果你已经给出了标签id列表,那么你可以在比赛阶段使用它。
db.bookmark.aggregate([
{
"$unwind": "$bookmarkTags"
},
{
"$lookup": {
"from": "tags",
"localField": "bookmarkTags.tagId",
"foreignField": "_id",
"as": "btags"
}
},
{
"$unwind": {
path: "$btags",
preserveNullAndEmptyArrays: true
}
},
{
"$group": {
"_id": "$btags._id",
"docs": {
"$push": "$btags"
}
}
},
{
"$project": {
tag_id: "$_id",
"count": {
"$size": "$docs"
},
_id: 0
}
}
])
我有两个集合,即“标签”和“书签”。
Tags documents:
{
"taggedBookmarksCount": 2,
"taggedNotesCount": 0,
"_id": "627a80e6b12b0dc78b3a6d4b",
"name": "Article"
},
{
"taggedBookmarksCount": 0,
"taggedNotesCount": 0,
"_id": "62797885b479b5906ef6ed43",
"name": "Client"
},
Bookmark Documents:
{
"_id": "627a814db12b0dc78b3a6d54",
"bookmarkTags": [
{
"tagId": "627a814db12b0dc78b3a6d55",
"tag": "Article"
},
{
"tagId": "627a814db12b0dc78b3a6d56",
"tag": "to be read"
}
],
"bookmarkTitle": "Please sorrow of work",
}
Objective是获取“标签”集合中所有标签的书签数。
下面是我当前的实现,returns 每个 tags.But 这个查询的书签计数需要大约 3 秒到 运行(REST API 响应时间) 20 个标签。
tags = await Tag.find(
{
userId: req.params.userId
},
{ _id: 1 }
);
tagIds = tags.map(tag => {
return tag._id.toString();
});
const tagCounts = await Promise.all(
tagIds.map(async tagId => {
const count = await Model.aggregate([
{
$match: {
bookmarkTags: {
$elemMatch: {
tagId: tagId
}
}
}
},
{
$group: {
_id: '_id',
count: {
$sum: 1
}
}
}
]);
return { tagId, count: count[0] ? count[0].count : 0 };
})
);
我假设它需要更长的时间,因为我正在映射所有标签,有多次往返 database.Please 建议减少查询执行时间的方法。
您可以按以下方式进行
db.bookmark.aggregate([
{
"$unwind": "$bookmarkTags" //Reshape tags
},
{
"$lookup": { //Do a join
"from": "tags",
"localField": "bookmarkTags.tagId",
"foreignField": "_id",
"as": "btags"
}
},
{
"$unwind": { //reshape the array elements
path: "$btags",
preserveNullAndEmptyArrays: true
}
},
{
"$group": { // Group tag wise bookmarks
"_id": "$bookmarkTags.tagId",
"docs": {
"$addToSet": "$btags"
}
}
},
{
"$project": { //Get counts, project what you want.
tag_id: "$_id",
"count": {
"$size": "$docs"
},
_id: 0
}
}
])
如果你已经给出了标签id列表,那么你可以在比赛阶段使用它。
db.bookmark.aggregate([
{
"$unwind": "$bookmarkTags"
},
{
"$lookup": {
"from": "tags",
"localField": "bookmarkTags.tagId",
"foreignField": "_id",
"as": "btags"
}
},
{
"$unwind": {
path: "$btags",
preserveNullAndEmptyArrays: true
}
},
{
"$group": {
"_id": "$btags._id",
"docs": {
"$push": "$btags"
}
}
},
{
"$project": {
tag_id: "$_id",
"count": {
"$size": "$docs"
},
_id: 0
}
}
])