mongodb - 基于通过 $lookup 检索的字段的多阶段聚合管道匹配数据
问题描述
我正在尝试在 MongoDB(4.4.9 社区版,使用pymongo
Python 3.10 的驱动程序)中构建一个复杂的嵌套聚合管道。
我想将不同集合中的相关数据点汇总到一个新的(理想情况下)视图(或者,如果这不起作用)集合中。
集合和其中的相关字段遵循层次结构。有members
,其中包含要在其上合并其他数据的顶级键,
membershipNumber
。
> members.find_one()
{'_id': ObjectId('61153299af6122XXXXXXXXXXXXX'), 'membershipNumber': 'N03XXXXXX'}
然后,有一个不同的集合,其中包含membershipNumber
,但也有一个不同的链接字段,an_user_id
。an_user_id
在其他集合中用于表示与该特定用户相关的数组中的记录/字段。
我“加入”members
并且an_users
喜欢这样:
result = members.aggregate([
{
'$lookup': {
'from': 'an_users',
'localField': 'membershipNumber',
'foreignField': 'memref',
'as': 'an_users'
}
},
{ '$unwind' : '$an_users' },
{
'$project' : {
'_id' : 1,
'membershipNumber' : 1,
'an_user_id' : '$an_users.user_id'
}
}
]);
到目前为止一切顺利,这将返回所需的聚合记录:
{'_id': ObjectId('61153253aBBBBBBBBBBBB'),
'membershipNumber': 'N0XXXXXXXX',
'an_user_id': '48XXXXXX'}
现在,我有第三个集合,它包含an_user_id
数组中的字符串,表示用户单击给定电子邮件的位置,其中记录是电子邮件(数组中的an_user_id
sclicks
是单击该电子邮件中链接的用户。
{'_id': ObjectId('blah'),
'email_id': '407XXX',
'actions_count': 17,
'administrative_title': 'test',
'bounce': ['3440XXXX'],
'click': ['38294CCC',
'418FFFF',
'48XXXXXX',
'38eGGGG'}
我想计算集合中数组(例如,,)中给定an_user_id
(我从聚合中获得)的出现次数,并将其包含在调用中,以检索如下内容:clicks
bounces
opens
emails
.aggregate
{'_id': ObjectId('61153253aBBBBBBBBBBBB'),
'membershipNumber': 'N0XXXXXXXX',
'an_user_id': '48XXXXXX',
'n_email_clicks' : 412,
'n_email_bounces' : 12
}
此外,我可能还想an_user_id
在我的数据库中附加其他集合中的计数。
考虑,例如,这个集合称为events
:
{
"_id": "617ffa96ee11844e143a63dd",
"id": "12345",
"administrative_title": "my_event",
"created_at": {
"$date": "2020-01-15T16:28:50.000Z"
},
"event_creator_id": "123456",
"event_title": "my_event",
"group_id": "123456",
"permalink": "event_id",
"rsvp_count": 54,
"rsvps": [{
"rsvp_id": "56789",
"display_name": "John Doe",
"rsvp_user_id": "48XXXXXX",
"rsvp_created_at": {
"$date": "2020-01-28T15:38:50.000Z"
},
"rsvp_updated_at": {
"$date": "2020-01-28T15:38:50.000Z"
},
"first_name": "John",
"last_name": "Doe",
}, {
"rsvp_id": "543895",
"display_name": "James Appleslice",
"rsvp_user_id": "N03XXXXXX",
"rsvp_created_at": {
"$date": "2020-02-05T13:15:14.000Z"
},
"rsvp_updated_at": {
"$date": "2020-02-05T13:15:14.000Z"
},
"first_name": "James",
"last_name": "Appleslice"}
]
}
所以,最终产品看起来像这样:
{'_id': ObjectId('61153253aBBBBBBBBBBBB'),
'membershipNumber': 'N0XXXXXXXX',
'an_user_id': '48XXXXXX',
'n_email_clicks' : 412,
'n_email_bounces' : 12,
'n_rsvps' : 12
}
我的想法是使用$lookup
参数 - 但是,我只知道如何使用它来匹配我正在执行聚合的父集合中的字段,而不是在过程中生成的字段聚合。
任何帮助将不胜感激!
解决方案
你可以使用$lookup
管道。首先,您将$lookup
用户 ID 后跟另一个$lookup
以验证用户 ID 是否存在于电子邮件中。最后还有几个阶段可以根据您的需要收集结果和格式。此外,$out
如果您想将结果写入另一个集合,您可以添加阶段。
db.members.aggregate([{
$lookup: {
from: "an_users",
let: {
membershipNumber: "$membershipNumber"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$memref",
"$$membershipNumber"
]
},
}
},
{
"$lookup": {
"from": "emails",
"localField": "user_id",
"foreignField": "click",
"as": "clicks"
}
},
{
"$project": {
"_id": 1,
"membershipNumber": 1,
"an_user_id": "$user_id",
"n_email_clicks": {
$size: "$clicks"
}
}
}
],
as: "details"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: [
"$details",
0
]
},
"$$ROOT"
]
}
}
},
{
$project: {
details: 0
}
}])
推荐阅读
- python - 使用 pandas 读取 csv 文件并显示带有排序日期/时间的单元格值
- ios - 使用 GCD 实现线程池
- python - 如何在流程结束之前生成和使用随机数?
- javascript - 自动 VBA 加载 IE 并在登录屏幕上输入凭据
- reactjs - 由于不同的类索引,使用 Styled-Components 的快照测试在 CI 管道中失败
- java - 如何在调用 setResult 后修复应用程序崩溃,然后使用 cameraapi2 从surfaceview 完成
- python - (Scrapy) 生成请求/生成和执行请求/执行请求
- linux - 为什么无法在 Ubuntu 中执行 katoolin?
- backup - 有哪些细微的问题会导致备份恢复失败?
- vim - Supertab 不得用于我的缩写设置