我用管道发现了Mongodb及其查询,而且我在案件中挣扎。
我正在寻找每个 pathsList 文档,在那里我可以找到从位置B到位置C的路径
假设我有来自pathsListsCollection的以下2个 pathsList 文档,它们有一个路径文档数组
-------------
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个路径列表文档。
现在,如何更改此聚合以仅查找具有positionStart = 10和positionFinal = 12的那个特定顺序的聚合 如果第一个表达式已经验证,如何尝试验证第二个表达式?
我在第一场$匹配后尝试切片路径数组$ $ slice,并继续查询其余部分,但无法找到任何明智的语法来执行此操作。
ie:使用第一个路径列表,我使用路径数组达到第一个$匹配:
[{
_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而不是pathListsCollection会更容易吗?
但是,我可以采用任何不同的方法,或者可以帮助我解决这个问题 提前致谢
答案 0 :(得分:1)
如果我收到了此消息,那么您希望根据此处的匹配positionStart
和positionFinish
进行“切片”。
如果您确实在"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
}
]
}
语法可能看起来有点短,但它可能不是性能最佳的选项,因为在实际执行$lookup
之前你无法“反向”查询"pathsCollection"
:
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
的方式的“反向案例”的最佳形式,可以在“explain”输出中看到:
{
"$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
。
<强> pathsCollection 强>
/* 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
}
<强> pathsListCollection 强>
/* 1 */
{
"_id" : ObjectId("595db5d8f5f11516540d1185"),
"pathIds" : [
ObjectId("595db4c7f5f11516540d1182"),
ObjectId("595db4c7f5f11516540d1183"),
ObjectId("595db4c7f5f11516540d1184")
]
}
/* 2 */
{
"_id" : ObjectId("595db62df5f11516540d1189"),
"pathIds" : [
ObjectId("595db616f5f11516540d1186"),
ObjectId("595db616f5f11516540d1187"),
ObjectId("595db616f5f11516540d1188")
]
}