gpt4 book ai didi

mongodb - 使用 $lookup 根据匹配条件对数组进行切片

转载 作者:可可西里 更新时间:2023-11-01 09:48:18 25 4
gpt4 key购买 nike

我发现了 Mongodb 及其使用管道的查询,我正在为一个案例而苦苦挣扎。

我正在寻找每个 pathsList 文档,我可以在其中找到从位置 B 到位置 C 的路径

  • 输入:10 和 12
  • 输出:[pathsList](我预计在此示例中只有 1 个结果,但更可能是稍后的数组)

假设我有 2 个来自 pathsListsCollection 的 pathsList 文档,它们有一组 path 文档

-------------
pathsList = {
_id: ObjectId(...),
pathIds: [path1Id, path2Id, path3Id]
}
-------------
path1 = {
_id: ObjectId(...),
positionStart: 8,
positionFinal: 10,
index:0
}
-------------
path2 = {
_id: ObjectId(...),
positionStart: 10,
positionFinal: 12,
index:1
}
-------------
path3 = {
_id: ObjectId(...),
positionStart: 12,
positionFinal: 14,
index:2
}
-------------

-------------
pathsList = {
_id: ObjectId(...),
pathIds: [path4Id, path5Id, path6Id]
}
-------------
path4 = {
_id: ObjectId(...),
positionStart: 14,
positionFinal: 12,
index:0
}
-------------
path5 = {
_id: ObjectId(...),
positionStart: 12,
positionFinal: 10,
index:1
}
-------------
path6 = {
_id: ObjectId(...),
positionStart: 10,
positionFinal: 8,
index:2
}
-------------

到目前为止,我已经做了这样的事情:

pathsListCollection.aggregate([
{
$lookup:{
from: "pathsCollection",
localField: "pathIds",
foreignField: "_id",
as: paths
}
},
{
$match:{
paths.positionStart : 10 // first input value
}
},
{
$match:{
paths.positionFinal : 12 // second input value
}
},
])

这样做我得到了 2 个 pathsList 文档。

现在,我如何更改此聚合以仅找到具有特定顺序的 positionStart = 10 和 positionFinal = 12 的聚合如何仅在第一个表达式已经验证时才尝试验证第二个表达式?

我研究了 $slice,试图在第一个 $match 之后对路径数组进行切片,并继续查询其余部分,但找不到任何相关的语法来执行此操作。

即:使用第一个 pathsList,我用 paths array 到达第一个 $match :

[{
_id: ObjectId(...),
positionStart: 8,
positionFinal: 10,
index:0
},
{
_id: ObjectId(...),
positionStart: 10, // first $match here
positionFinal: 12,
index:1
},
{
_id: ObjectId(...),
positionStart: 12,
positionFinal: 14,
index:2
}]

我想在这样的数组上进行下一个 $match :

[{
_id: ObjectId(...),
positionStart: 10,
positionFinal: 12, // second $match has to start from this elem of the array
index:1
},
{
_id: ObjectId(...),
positionStart: 12,
positionFinal: 14,
index:2
}]

这有可能吗?首先查询 pathsCollection 而不是 pathsListsCollection 会更容易吗?

但是,我愿意接受任何可以帮助我解决该问题的不同方法或想法提前致谢

最佳答案

如果我得到这个,那么你想根据给定的匹配 positionStartpositionFinish 在这里“切片”。

最优情况

如果您确实在 "pathsCollection" 上开始查询,实际上性能会更好,因为这是您实际要匹配项目的地方。所以 $match应该“首先”完成并使用 $or在范围内“切片”的表达式:

然后用 $lookup然后,您将只返回 "pathsListCollection" 项,使用“切片”数组格式化:

在您的数据的最小样本上,从“开始”10 到“完成”12 将是:

db.getCollection('pathsCollection').aggregate([
{ "$match": {
"positionStart": { "$gte": 10, "$lte": 12 },
"positionFinal": { "$gte": 10, "$lte": 12 }
}},
{ "$lookup": {
"from": "pathsListCollection",
"localField": "_id",
"foreignField": "pathIds",
"as": "pathsList"
}},
{ "$unwind": "$pathsList" },
{ "$addFields": {
"pathsList.pathIds": {
"$filter": {
"input": "$pathsList.pathIds",
"as": "p",
"cond": { "$eq": [ "$_id", "$$p" ] }
}
}
}},
{ "$unwind": "$pathsList.pathIds" },
{ "$group": {
"_id": "$pathsList._id",
"pathIds": {
"$push": {
"_id": "$_id",
"positionStart": "$positionStart",
"positionFinal": "$positionFinal",
"index": "$index"
}
}
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionStart",
0
]},
10
]},
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionFinal",
-1
]},
12
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])

会产生:

/* 1 */
{
"_id" : ObjectId("595db5d8f5f11516540d1185"),
"pathIds" : [
{
"_id" : ObjectId("595db4c7f5f11516540d1183"),
"positionStart" : 10.0,
"positionFinal" : 12.0,
"index" : 1.0
}
]
}

并且将“范围”缩小到“开始”10 和“完成”14,这将是:

db.getCollection('pathsCollection').aggregate([
{ "$match": {
"positionStart": { "$gte": 10, "$lte": 14 },
"positionFinal": { "$gte": 10, "$lte": 14 }
}},
{ "$lookup": {
"from": "pathsListCollection",
"localField": "_id",
"foreignField": "pathIds",
"as": "pathsList"
}},
{ "$unwind": "$pathsList" },
{ "$addFields": {
"pathsList.pathIds": {
"$filter": {
"input": "$pathsList.pathIds",
"as": "p",
"cond": { "$eq": [ "$_id", "$$p" ] }
}
}
}},
{ "$unwind": "$pathsList.pathIds" },
{ "$group": {
"_id": "$pathsList._id",
"pathIds": {
"$push": {
"_id": "$_id",
"positionStart": "$positionStart",
"positionFinal": "$positionFinal",
"index": "$index"
}
}
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionStart",
0
]},
10
]},
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionFinal",
-1
]},
14
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])

制作:

/* 1 */
{
"_id" : ObjectId("595db5d8f5f11516540d1185"),
"pathIds" : [
{
"_id" : ObjectId("595db4c7f5f11516540d1183"),
"positionStart" : 10.0,
"positionFinal" : 12.0,
"index" : 1.0
},
{
"_id" : ObjectId("595db4c7f5f11516540d1184"),
"positionStart" : 12.0,
"positionFinal" : 14.0,
"index" : 2.0
}
]
}

反转大小写

它的语法可能看起来有点短,但它可能不是性能最好的选项,因为您不能在相反的情况下“查询”“pathsCollection”,直到 $lookup。实际执行:

db.pathsListCollection.aggregate([
{ "$lookup": {
"from": "pathsCollection",
"localField": "pathIds",
"foreignField": "_id",
"as": "pathIds"
}},
{ "$unwind": "$pathIds" },
{ "$match": {
"pathIds.positionStart": { "$gte": 10, "$lte": 14 },
"pathIds.positionFinal": { "$gte": 10, "$lte": 14 }
}},
{ "$group": {
"_id": "$_id",
"pathIds": { "$push": "$pathIds" }
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionStart",
0
]},
10
]},
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionFinal",
-1
]},
14
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])

这是关于 MongoDB 如何实际发布 $lookup 的“反向案例”的最佳形式。当应用于服务器时,可以在“解释”输出中看到:

    {
"$lookup" : {
"from" : "pathsCollection",
"as" : "pathIds",
"localField" : "pathIds",
"foreignField" : "_id",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"$and" : [
{
"positionStart" : {
"$gte" : 10.0
}
},
{
"positionStart" : {
"$lte" : 14.0
}
},
{
"positionFinal" : {
"$gte" : 10.0
}
},
{
"positionFinal" : {
"$lte" : 14.0
}
}
]
}
}
},
{
"$group" : {

在那里显示 $unwind$match已经“神奇地”消失了。他们现在当然已经“卷起”到 $lookup 中了。这样当查询相关数据时,你实际上只会那些符合给定条件的结果。

“非最佳”方法是 $filter反而。但实际上来自相关集合的 ALL 结果被返回,然后只有在“完整”数组已经存在时才被删除:

db.pathsListCollection.aggregate([
{ "$lookup": {
"from": "pathsCollection",
"localField": "pathIds",
"foreignField": "_id",
"as": "pathIds"
}},
{ "$addFields": {
"pathIds": {
"$filter": {
"input": "$pathIds",
"as": "p",
"cond": {
"$and": [
{ "$gte": [ "$$p.positionStart", 10 ] },
{ "$lte": [ "$$p.positionStart", 14 ] },
{ "$gte": [ "$$p.positionFinal", 10 ] },
{ "$lte": [ "$$p.positionFinal", 14 ] },
]
}
}
}
}},
{ "$match": {
"pathIds": {
"$elemMatch": {
"positionStart": { "$gte": 10, "$lte": 14 },
"positionFinal": { "$gte": 10, "$lte": 14 }
}
}
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionStart",
0
]},
10
]},
{ "$eq": [
{ "$arrayElemAt": [
"$pathIds.positionFinal",
-1
]},
14
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])

还注意到您仍然需要 $match$redact鉴于在这种情况下生成的数组条目仍然满足条件,并且由于 $filter 的结果,数组实际上不是“空”的.


使用的样本

路径集合

/* 1 */
{
"_id" : ObjectId("595db4c7f5f11516540d1182"),
"positionStart" : 8.0,
"positionFinal" : 10.0,
"index" : 0.0
}

/* 2 */
{
"_id" : ObjectId("595db4c7f5f11516540d1183"),
"positionStart" : 10.0,
"positionFinal" : 12.0,
"index" : 1.0
}

/* 3 */
{
"_id" : ObjectId("595db4c7f5f11516540d1184"),
"positionStart" : 12.0,
"positionFinal" : 14.0,
"index" : 2.0
}

/* 4 */
{
"_id" : ObjectId("595db616f5f11516540d1186"),
"positionStart" : 14.0,
"positionFinal" : 12.0,
"index" : 0.0
}

/* 5 */
{
"_id" : ObjectId("595db616f5f11516540d1187"),
"positionStart" : 12.0,
"positionFinal" : 10.0,
"index" : 1.0
}

/* 6 */
{
"_id" : ObjectId("595db616f5f11516540d1188"),
"positionStart" : 10.0,
"positionFinal" : 8.0,
"index" : 2.0
}

路径列表集合

/* 1 */
{
"_id" : ObjectId("595db5d8f5f11516540d1185"),
"pathIds" : [
ObjectId("595db4c7f5f11516540d1182"),
ObjectId("595db4c7f5f11516540d1183"),
ObjectId("595db4c7f5f11516540d1184")
]
}

/* 2 */
{
"_id" : ObjectId("595db62df5f11516540d1189"),
"pathIds" : [
ObjectId("595db616f5f11516540d1186"),
ObjectId("595db616f5f11516540d1187"),
ObjectId("595db616f5f11516540d1188")
]
}

关于mongodb - 使用 $lookup 根据匹配条件对数组进行切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44917069/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com