如何验证MongoDB上的数组是否包含顺序项?

如何验证MongoDB上的数组是否包含顺序项?,mongodb,mongodb-query,Mongodb,Mongodb Query,如果我在Mongo上有一个具有以下结构的文档,如何验证dataarray是否包含两个或多个具有相同值的属性,一个接一个 在本例中,我的目标是指出,在集合中的所有文档中,此文档有两个具有相同值的状态(“status_B”) 我知道如何计算一个状态在数据数组中出现的次数,但我需要找出在哪些文档中两个或多个状态按顺序出现 { "_id": ObjectId("XYZ"), "data": [ { "status": "status_A",

如果我在Mongo上有一个具有以下结构的文档,如何验证
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”