我正在编写用户详细信息API视图,并希望添加is_following
标记,以指示经过身份验证的API用户(用户A )是否关注了&# 39;他们正在查看的个人资料(用户B )。
在请求时,我只有经过身份验证的API用户_id
。我可以在一个查询中获取经过身份验证的API用户的following
字段,然后继续为他们有兴趣查看的用户进行第二次查询,但我认为将该工作传递给数据库在单个聚合中(如果可能)。
假设我有users
集合的以下架构:
[
{
_id: 1,
name: 'David',
following: [2, 3] // David follows Sam and Lucy
},
{
_id: 2,
name: 'Sam',
following: [1] // Sam only follows David
},
{
_id: 3,
name: 'Lucy',
following: [1, 2] // Lucy follows David and Sam
},
]
我想知道是否可以按照我目前的方式编写聚合:
_id
following
数组存储在汇总管道中,以便以后用于我们希望查看的用户_id
is_following
,表示用户B 的_id
是否在经过身份验证的API用户中(用户A )我们之前存储的following
数组。即登录用户正在关注他们当前正在查看的用户的个人资料。我不确定的第2步和第3步,我不确定是否可以在单个聚合查询中实现抓取具有不同$match
条件的两个文档的方法
编辑:添加预期输出
如果经过身份验证的用户(用户A )为_id
2,则已查看的用户用户B 为_id
1:< / p>
{
_id: 1,
name: 'David',
following: [2, 3],
is_following: true
}
如果经过身份验证的用户(用户A )为_id
2,并且已查看的用户用户B 为_id
3:
{
_id: 3,
name: 'Lucy',
following: [1, 2],
is_following: false
}
答案 0 :(得分:0)
在您的问题中不是100%明确,但您似乎在查找相同数据的简单$lookup
,并与结果用户进行比较。您可能实际上一次只希望这个用户,因此该用户的$match
通常是&#34;选项&#34;这里。
除了标准$lookup
结果之外,其他内容并不多,然后使用$map
与&#34; parent&#34;进行比较。 _id
并将新属性添加到数组中。
理想情况下,使用MongoDB 3.6,您可以应用$mergeObjects
:
Person.aggregate([
// { "$match": { "_id": 3 } },
{ "$lookup": {
"from": Person.collection.name,
"localField": "following",
"foreignField": "_id",
"as": "following"
}},
{ "$addFields": {
"following": {
"$map": {
"input": "$following",
"in": {
"$mergeObjects": [
"$$this",
{ "is_following": {
"$in": [ "$_id", "$$this.following" ]
}}
]
}
}
}
}}
])
对于早期版本,您只需要明确命名字段&#34;&#34;在您要返回的$map
内:
Person.aggregate([
// { "$match": { "_id": 3 } },
{ "$lookup": {
"from": Person.collection.name,
"localField": "following",
"foreignField": "_id",
"as": "following"
}},
{ "$project": {
"_id": 1,
"name": 1,
"following": {
"$map": {
"input": "$following",
"in": {
"_id": "$$this._id",
"name": "$$this.name",
"following": "$$this.following",
"is_following": { "$setIsSubset": [["$_id"], "$$this.following"] }
}
}
}
}}
])
基础知识是$map
检查每个元素时,您可以对自己的"followers"
数组和当前用户_id
值进行比较。 $in
或$setIsSubset
适用于此类比较。一个比较一个值与一个数组和另一个&#34;两个&#34;阵列。
或者,您甚至无法访问$lookup
,.populate()
,然后只需&#34;重新映射&#34;数组内容的方式大致相同:
let people = await Person.find().lean().populate('following');
people = people.map(p => ({
...p,
following: p.following.map(f => ({
...f,
is_following: f.following.some(e => e._id.equals(p._id))
}))
}));
使用Array.some()
ObjectID.equals()
方法进行比较。请注意,Array.includes()
无法在此处应用,而不会将ObjectId
值重新映射到字符串,因为&#34;对象比较&#34;的工作原理。
此处的所有表格都会得出相同的结果:
{
"_id" : 1,
"name" : "David",
"following" : [
{
"_id" : 2,
"name" : "Sam",
"following" : [
1
],
"is_following" : true
},
{
"_id" : 3,
"name" : "Lucy",
"following" : [
1,
2
],
"is_following" : true
}
]
}
{
"_id" : 2,
"name" : "Sam",
"following" : [
{
"_id" : 1,
"name" : "David",
"following" : [
2,
3
],
"is_following" : true
}
]
}
{
"_id" : 3,
"name" : "Lucy",
"following" : [
{
"_id" : 1,
"name" : "David",
"following" : [
2,
3
],
"is_following" : true
},
{
"_id" : 2,
"name" : "Sam",
"following" : [
1
],
"is_following" : false
}
]
}