API 在聚合中使用多个 $lookup 时需要很长时间才能响应
API taking much time to response when using mulitiple $lookup in aggregation
我正在使用下面的代码获取用户对话
对话模式
const conversationSchema = new Schema({
userIdSender: {
type: Schema.Types.ObjectId,
ref: 'user',
},
userIdReceiver: {
type: Schema.Types.ObjectId,
ref: 'user',
},
isRead: {
type: Boolean,
default: false,
},
isEmailSent: {
type: Boolean,
default: false,
},
readPendingFrom: {
type: String,
default: ''
},
dateCreated: {
type: Date,
},
dateUpdated: {
type: Date,
},
isDeleted: {
type: Number,
default: 0,
},
})
在我的用户模式中,我有一个“isBlocked”字段。我正在尝试获取“isBlocked”为假的用户之间的所有对话。我正在使用以下聚合来实现这一点。
const conversationPipeline: any = [
{
$match: {
'$or': [
{
'userIdReceiver': userDetailsFromToken._id,
},
{
'userIdSender': userDetailsFromToken._id,
}
],
}
},
{
$lookup: {
from: 'users',
localField: 'userIdReceiver',
foreignField: '_id',
as: 'userReveiver'
}
},
{ $unwind: '$userReveiver' },
{ $match: { 'userReveiver.isBlocked': false } },
{
$lookup: {
from: 'users',
localField: 'userIdSender',
foreignField: '_id',
as: 'userSender'
}
},
{ $unwind: '$userSender' },
{ $match: { 'userSender.isBlocked': false } },
{
$project: {
_id: 1,
dateUpdated: 1,
isRead: 1,
readPendingFrom: { $ifNull: ['$readPendingFrom', ''] },
userIdSender: 1,
flag: {
$cond: [
{$eq: ['$readPendingFrom' , String(userDetailsFromToken?._id)]},
1,
0
]
},
userIdReceiver: 1,
senderBlockList: { $ifNull: ['$senderConnections.userBlockList', []] },
receiverBlockList: { $ifNull: ['$receiverConnections.userBlockList', []] }
}
},
{$sort:{flag:-1,dateUpdated:-1}},
{ $skip: Number(offset) || 0 },
{ $limit: Number(limit) || 20 }
]
我收到以下想要的回复
"data": {
"message": "OK",
"count": 142226,
"conversations": [
{
"receiverUser": {
"profilePicUrl": "",
"isBlocked": false,
"_id": "0000",
"firstName": "Demo",
"lastName": "Demo",
"username": "Demo_Demo",
"dateUpdated": "2022-02-14T01:37:03.123Z",
"userConnectionId": {
"userNetworks": [],
"pendingRequests": [],
"sentRequests": [],
"userBlockList": [],
"isDeleted": 0,
"_id": "0000",
"userId": "0000",
"dateCreated": "2022-02-14T01:34:17.539Z",
"dateUpdated": "2022-02-14T01:34:17.539Z",
"__v": 0
}
},
"senderUser": {
"profilePicUrl": "1/profile_photo_4365136bb203ab.jpg",
"isBlocked": false,
"_id": "123",
"firstName": "Tea",
"lastName": "Tdsadeam",
"username": "arsdatmo",
"dateUpdated": "2022-02-14T01:55:05.571Z",
"userConnectionId": {
"userNetworks": [
],
"pendingRequests": [],
"sentRequests": [],
"userBlockList": [],
"isDeleted": 0,
"_id": "123",
"userId": "123",
"__v": 0,
"dateUpdated": "2022-02-10T17:53:03.285Z",
"oldUserConnectionId": "1"
}
},
"_id": "6209b199cc39c2001dd4d003",
"dateUpdated": "2022-02-14T01:40:06.846Z",
"isRead": false,
"readPendingFrom": "0000",
"senderBlockList": [],
"receiverBlockList": []
}
],
"chatThreadExist": false,
"userNotExist": null
}
使用上面的查询我可以得到想要的结果,但是 api 获取数据的时间太长了。
有什么办法可以优化上面的代码吗
这是一个骨架聚合管道,它使用单个 "$lookup"
和 "$match"
来排除 "isBlocked": true
用户。希望这就足够了,这样您就可以了解如何将类似的东西合并到您的聚合管道中……并希望它更有效率。
db.conversations.aggregate([
{ // select sender or receiver
$match: {
"$or": [
{ "userIdReceiver": 16 },
{ "userIdSender": 16 }
]
}
},
{ // lookup the users
"$lookup": {
"from": "users",
"let": {
"userIdSender": "$userIdSender",
"userIdReceiver": "$userIdReceiver"
},
"pipeline": [
{ // only need this conversation's users
"$match": {
"$expr": {
"$in": [
"$_id",
[ "$$userIdSender", "$$userIdReceiver" ]
]
}
}
},
{ // only care if they are blocked
"$project": {
"_id": 0,
"isBlocked": 1
}
}
],
"as": "blockTest"
}
},
{ // eliminate conversations where either user is blocked
"$match": {
"$expr": { "$or": "$blockTest.isBlocked" }
}
},
{ // don't need lookup info anymore
"$unset": "blockTest"
}
])
在 mongoplayground.net 上试用。
我正在使用下面的代码获取用户对话
对话模式
const conversationSchema = new Schema({
userIdSender: {
type: Schema.Types.ObjectId,
ref: 'user',
},
userIdReceiver: {
type: Schema.Types.ObjectId,
ref: 'user',
},
isRead: {
type: Boolean,
default: false,
},
isEmailSent: {
type: Boolean,
default: false,
},
readPendingFrom: {
type: String,
default: ''
},
dateCreated: {
type: Date,
},
dateUpdated: {
type: Date,
},
isDeleted: {
type: Number,
default: 0,
},
})
在我的用户模式中,我有一个“isBlocked”字段。我正在尝试获取“isBlocked”为假的用户之间的所有对话。我正在使用以下聚合来实现这一点。
const conversationPipeline: any = [
{
$match: {
'$or': [
{
'userIdReceiver': userDetailsFromToken._id,
},
{
'userIdSender': userDetailsFromToken._id,
}
],
}
},
{
$lookup: {
from: 'users',
localField: 'userIdReceiver',
foreignField: '_id',
as: 'userReveiver'
}
},
{ $unwind: '$userReveiver' },
{ $match: { 'userReveiver.isBlocked': false } },
{
$lookup: {
from: 'users',
localField: 'userIdSender',
foreignField: '_id',
as: 'userSender'
}
},
{ $unwind: '$userSender' },
{ $match: { 'userSender.isBlocked': false } },
{
$project: {
_id: 1,
dateUpdated: 1,
isRead: 1,
readPendingFrom: { $ifNull: ['$readPendingFrom', ''] },
userIdSender: 1,
flag: {
$cond: [
{$eq: ['$readPendingFrom' , String(userDetailsFromToken?._id)]},
1,
0
]
},
userIdReceiver: 1,
senderBlockList: { $ifNull: ['$senderConnections.userBlockList', []] },
receiverBlockList: { $ifNull: ['$receiverConnections.userBlockList', []] }
}
},
{$sort:{flag:-1,dateUpdated:-1}},
{ $skip: Number(offset) || 0 },
{ $limit: Number(limit) || 20 }
]
我收到以下想要的回复
"data": {
"message": "OK",
"count": 142226,
"conversations": [
{
"receiverUser": {
"profilePicUrl": "",
"isBlocked": false,
"_id": "0000",
"firstName": "Demo",
"lastName": "Demo",
"username": "Demo_Demo",
"dateUpdated": "2022-02-14T01:37:03.123Z",
"userConnectionId": {
"userNetworks": [],
"pendingRequests": [],
"sentRequests": [],
"userBlockList": [],
"isDeleted": 0,
"_id": "0000",
"userId": "0000",
"dateCreated": "2022-02-14T01:34:17.539Z",
"dateUpdated": "2022-02-14T01:34:17.539Z",
"__v": 0
}
},
"senderUser": {
"profilePicUrl": "1/profile_photo_4365136bb203ab.jpg",
"isBlocked": false,
"_id": "123",
"firstName": "Tea",
"lastName": "Tdsadeam",
"username": "arsdatmo",
"dateUpdated": "2022-02-14T01:55:05.571Z",
"userConnectionId": {
"userNetworks": [
],
"pendingRequests": [],
"sentRequests": [],
"userBlockList": [],
"isDeleted": 0,
"_id": "123",
"userId": "123",
"__v": 0,
"dateUpdated": "2022-02-10T17:53:03.285Z",
"oldUserConnectionId": "1"
}
},
"_id": "6209b199cc39c2001dd4d003",
"dateUpdated": "2022-02-14T01:40:06.846Z",
"isRead": false,
"readPendingFrom": "0000",
"senderBlockList": [],
"receiverBlockList": []
}
],
"chatThreadExist": false,
"userNotExist": null
}
使用上面的查询我可以得到想要的结果,但是 api 获取数据的时间太长了。 有什么办法可以优化上面的代码吗
这是一个骨架聚合管道,它使用单个 "$lookup"
和 "$match"
来排除 "isBlocked": true
用户。希望这就足够了,这样您就可以了解如何将类似的东西合并到您的聚合管道中……并希望它更有效率。
db.conversations.aggregate([
{ // select sender or receiver
$match: {
"$or": [
{ "userIdReceiver": 16 },
{ "userIdSender": 16 }
]
}
},
{ // lookup the users
"$lookup": {
"from": "users",
"let": {
"userIdSender": "$userIdSender",
"userIdReceiver": "$userIdReceiver"
},
"pipeline": [
{ // only need this conversation's users
"$match": {
"$expr": {
"$in": [
"$_id",
[ "$$userIdSender", "$$userIdReceiver" ]
]
}
}
},
{ // only care if they are blocked
"$project": {
"_id": 0,
"isBlocked": 1
}
}
],
"as": "blockTest"
}
},
{ // eliminate conversations where either user is blocked
"$match": {
"$expr": { "$or": "$blockTest.isBlocked" }
}
},
{ // don't need lookup info anymore
"$unset": "blockTest"
}
])
在 mongoplayground.net 上试用。