Mongo查询查找不同匹配元素后没有匹配元素的位置

时间:2016-05-26 21:43:19

标签: mongodb mongodb-query aggregation-framework

我正在尝试使用以下文档查询MongoDB集合(我无法控制),这些文档用作每个作业定义的作业日志:

{
    "definition": ...,
    "jobs": [ // sequential
        {
            "time": ...,
            "result": "success"
        },
        {
            "time": ... (after previous),
            "result": "failure"
        }
        {
            "time": ...,
            "result": "running"
        }
    ]
}

我想找到每个作业定义,其中最近的已完成作业运行失败,其中“失败”和“成功”是唯一两个“已完成”的结果类型,但可能有任何我不知道的其他结果的数量。

到目前为止,我已经想出了这个找到所有失败的工作:

db.collection.find({jobs: {$elemMatch: {result: "failure"}}})

我当然可以获取失败列表并以编程方式搜索过滤那些符合我的特定要求的内容,如果使用纯mongo无法做到这一点。

修改

我被限制使用mongo 2.6。我可以忽略任何非失败和不成功的结果,但在成功和失败结果之前,之后和之间可能存在任意数量。

2 个答案:

答案 0 :(得分:0)

您可以使用聚合框架

  db.robert.aggregate([     
         {
            $project : {
                _id : 1,
                def : 1,
                jobs : { //filter only fields by OK/NOK
                    $filter : {
                        input : "$jobs",
                        as : "item",
                        cond : {
                            $or : [{
                                    $eq :
                                    [{
                                            $cmp : ["$$item.staus", "success"]
                                        }, 0]
                                }, {
                                    $eq : [{
                                            $cmp : ["$$item.staus", "failure"]
                                        }, 0]
                                }
                            ]

                        }

                    }
                }
            }
        },
        {
            $project : {
                _id : 1,
                def : 1,
                jobs : {
                    $slice : ["$jobs", 2]//take first two entries of array
                    // this could be also last two use -2
                }
            }
        }, {
            $match : {
                jobs : {
                    $size : 2 //eliminate nulls and only one entry in the array
                }
            }
        }, {
            $project : { // this is a kind of creating parameters for $match
                _id : 1,
                def : 1,
                firstShouldBeFalied : {
                    $slice : ["$jobs", 1]
                },
                secondShouldBeSuccess : {
                    $slice : ["$jobs", 1, 1]
                },
            }
        }, {
            $match : {

                $and : [{
                        "firstShouldBeFalied.staus" : "failure"
                    }, {
                        "secondShouldBeSuccess.staus" : "success"
                    },
                ]

            }
        },

    ])

欢迎任何评论!

答案 1 :(得分:0)

这超出了基本的find()查询。您需要使用聚合框架。

最有效的方法是使用MongoDB 3.2或更高版本,因为我们可以在$slice阶段使用$arrayElemAt$project来获取最后一个元素使用索引-1的数组,但在这里你应该使用$arrayElemAt因为它返回元素,而$slice返回一个元素数组。此外,您需要使用$let运算符使用dot notation访问子文档中的“结果”字段。

管道中的第一阶段必须是$match阶段。这减少了通过线路发送的数据量以及管道中使用的时间和内存。

管道中的最后一个阶段也是$match阶段,您只选择符合条件的文档。

db.collection.aggregate([
    { "$match": { "jobs.result": "failure" } }, 
    { "$project": { 
        "definition": 1,
        "result": { 
            "$let": { 
                "vars": { "job": { "$arrayElemAt": [ "$jobs", -1 ] } },
                "in": "$$job.result" 
            } 
        } 
    }}, 
    { "$match": { "result": "failure" } } 
])

从MongoDB 3.0向后,您需要一种效率较低的不同方法,因为它意味着您在_id匹配和$unwind文档后$group“作业”数组,使用$last累加器运算符来获取数组中的最后一个元素。当然,组阶段中的$first运算符用于保留“定义”字段值。

对文档进行分组后,您需要使用$redact管道阶段,当条件为{时,使用逻辑条件将$$KEEP文档返回到最后一个“作业”符合条件的所有文档{1}}或true它位于$$PRUNE

最后一个阶段是false,您可以在其中指定要包含在结果中的字段。这也减少了通过线路发送的数据量以及用于解码客户端文档的时间和内存。

$project