如何验证MongoDB上的数组是否包含顺序项?
如果我在Mongo上有一个具有以下结构的文档,如何验证如何验证MongoDB上的数组是否包含顺序项?,mongodb,mongodb-query,Mongodb,Mongodb Query,如果我在Mongo上有一个具有以下结构的文档,如何验证dataarray是否包含两个或多个具有相同值的属性,一个接一个 在本例中,我的目标是指出,在集合中的所有文档中,此文档有两个具有相同值的状态(“status_B”) 我知道如何计算一个状态在数据数组中出现的次数,但我需要找出在哪些文档中两个或多个状态按顺序出现 { "_id": ObjectId("XYZ"), "data": [ { "status": "status_A",
data
array是否包含两个或多个具有相同值的属性,一个接一个
在本例中,我的目标是指出,在集合中的所有文档中,此文档有两个具有相同值的状态(“status_B”)
我知道如何计算一个状态在数据
数组中出现的次数,但我需要找出在哪些文档中两个或多个状态按顺序出现
{
"_id": ObjectId("XYZ"),
"data": [
{
"status": "status_A",
"other": "data"
},
{
"status": "status_B",
"other": "data"
},
{
"status": "status_B",
"other": "data"
}
]
}
$map
和$range
到救援。它们一起允许您在阵列上制作“for循环”。给定如下输入集:
[
{_id:0,
"data": [
{ "status": "status_A", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_C", "other": "data" },
{ "status": "status_D", "other": "data" }
]
}
,{_id:1,
"data": [
{ "status": "status_A", "other": "data" },
{ "status": "status_X", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_X", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_D", "other": "data" },
{ "status": "status_D", "other": "data" }
]
}
]
然后,此管道将识别数据
数组中状态
字段在n
和n+1
项中的位置:
db.foo.aggregate([
{$project: {dupe: {$map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$cond: [ {$eq: [
// Important trick: $arrayElemAt[array,n] will give you the whole object at offset n.
// $arrayElemAt[arr plus dotpath into object, n] will give you just the field at the
// dotpath; in our case here, status is a single scalar string:
{$arrayElemAt: ["$data.status", "$$z"]},
{$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
]},
{$arrayElemAt: ["$data.status", "$$z"]},null]}
}}
}}
]);
产生:
{ "_id" : 0, "dupe" : [ null, null, null ] }
{
"_id" : 1,
"dupe" : [
null,
null,
"status_B",
"status_B",
null,
null,
"status_B",
null,
"status_D"
]
}
{ "_id" : 0, "dupe" : false }
{ "_id" : 1, "dupe" : true }
通过使用$let
设置变量,有些人可能会发现管道更容易:
db.foo.aggregate([
{$project: {dupe: {$map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$let: {
vars: { n0: {$arrayElemAt: ["$data.status", "$$z"]},
n1: {$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
},
in: {$cond: [ {$eq: [ "$$n0", "$$n1" ]}, "$$n0", null ]}
}}
}}
}}
]);
如果您想要一个更简单的结果,告诉您任何状态是否被n/n+1复制了任意次数,请使用$anyElementTrue
获得一个简单的布尔输出:
db.foo.aggregate([
{$project: {dupe: {$anyElementTrue: { $map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$cond: [ {$eq: [
{$arrayElemAt: ["$data.status", "$$z"]},
{$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
]},
{$arrayElemAt: ["$data.status", "$$z"]},null]}
}}
}
}}
]);
产生:
{ "_id" : 0, "dupe" : [ null, null, null ] }
{
"_id" : 1,
"dupe" : [
null,
null,
"status_B",
"status_B",
null,
null,
"status_B",
null,
"status_D"
]
}
{ "_id" : 0, "dupe" : false }
{ "_id" : 1, "dupe" : true }
$map
和$range
到救援。它们一起允许您在阵列上制作“for循环”。给定如下输入集:
[
{_id:0,
"data": [
{ "status": "status_A", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_C", "other": "data" },
{ "status": "status_D", "other": "data" }
]
}
,{_id:1,
"data": [
{ "status": "status_A", "other": "data" },
{ "status": "status_X", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_X", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_B", "other": "data" },
{ "status": "status_D", "other": "data" },
{ "status": "status_D", "other": "data" }
]
}
]
然后,此管道将识别数据
数组中状态
字段在n
和n+1
项中的位置:
db.foo.aggregate([
{$project: {dupe: {$map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$cond: [ {$eq: [
// Important trick: $arrayElemAt[array,n] will give you the whole object at offset n.
// $arrayElemAt[arr plus dotpath into object, n] will give you just the field at the
// dotpath; in our case here, status is a single scalar string:
{$arrayElemAt: ["$data.status", "$$z"]},
{$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
]},
{$arrayElemAt: ["$data.status", "$$z"]},null]}
}}
}}
]);
产生:
{ "_id" : 0, "dupe" : [ null, null, null ] }
{
"_id" : 1,
"dupe" : [
null,
null,
"status_B",
"status_B",
null,
null,
"status_B",
null,
"status_D"
]
}
{ "_id" : 0, "dupe" : false }
{ "_id" : 1, "dupe" : true }
通过使用$let
设置变量,有些人可能会发现管道更容易:
db.foo.aggregate([
{$project: {dupe: {$map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$let: {
vars: { n0: {$arrayElemAt: ["$data.status", "$$z"]},
n1: {$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
},
in: {$cond: [ {$eq: [ "$$n0", "$$n1" ]}, "$$n0", null ]}
}}
}}
}}
]);
如果您想要一个更简单的结果,告诉您任何状态是否被n/n+1复制了任意次数,请使用$anyElementTrue
获得一个简单的布尔输出:
db.foo.aggregate([
{$project: {dupe: {$anyElementTrue: { $map: {
input: {$range:[0, {$add:[{$size:"$data"},-1]} ]},
as: "z",
in: {$cond: [ {$eq: [
{$arrayElemAt: ["$data.status", "$$z"]},
{$arrayElemAt: ["$data.status", {$add:["$$z",1]} ]}
]},
{$arrayElemAt: ["$data.status", "$$z"]},null]}
}}
}
}}
]);
产生:
{ "_id" : 0, "dupe" : [ null, null, null ] }
{
"_id" : 1,
"dupe" : [
null,
null,
"status_B",
"status_B",
null,
null,
"status_B",
null,
"status_D"
]
}
{ "_id" : 0, "dupe" : false }
{ "_id" : 1, "dupe" : true }
聚合检查两个连续的
数据
数组元素是否具有相同的状态
值,并打印这些文档
使用以下两个示例文档:
{
"_id" : 1,
"data" : [
{
"status" : "status_A",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
}
]
},
{
"_id" : 2,
"data" : [
{
"status" : "status_B",
"other" : "data"
},
{
"status" : "status_A",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
}
]
}
聚合查询:
db.collection.aggregate( [
{
$addFields: {
matches: {
$reduce: {
input: "$data",
initialValue: { prev_status: "", has_seq: false },
in: {
$cond: [ { $eq: [ "$$value.prev_status", "$$this.status" ] },
{ has_seq: true, prev_status: "$$this.status" },
{ has_seq: "$$value.is_seq", prev_status: "$$this.status" }
]
}
}
}
}
},
{
$match: { "matches.has_seq": true }
},
{
$project: { matches: 0 }
}
] )
结果是具有
\u id:1
的文档,该文档具有具有状态的连续数组元素:“status\u B”
聚合检查两个连续的数据
数组元素是否具有相同的状态
值,并打印这些文档
使用以下两个示例文档:
{
"_id" : 1,
"data" : [
{
"status" : "status_A",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
}
]
},
{
"_id" : 2,
"data" : [
{
"status" : "status_B",
"other" : "data"
},
{
"status" : "status_A",
"other" : "data"
},
{
"status" : "status_B",
"other" : "data"
}
]
}
聚合查询:
db.collection.aggregate( [
{
$addFields: {
matches: {
$reduce: {
input: "$data",
initialValue: { prev_status: "", has_seq: false },
in: {
$cond: [ { $eq: [ "$$value.prev_status", "$$this.status" ] },
{ has_seq: true, prev_status: "$$this.status" },
{ has_seq: "$$value.is_seq", prev_status: "$$this.status" }
]
}
}
}
}
},
{
$match: { "matches.has_seq": true }
},
{
$project: { matches: 0 }
}
] )
结果是具有\u id:1
的文档,它具有具有状态的连续数组元素:“status\u B”