如何返回不同的$或mongodb?

时间:2015-03-07 21:35:37

标签: mongodb mongodb-query aggregation-framework

所以我有这个查询

db.collection.find($or:[{data_id:123},{data_id:345},{data_id:443}]);

如何调整它以仅返回$或的每个部分中的一个。 I.E类似于SQL:

SELECT DISTINCT data_id, [...] WHERE data_id='123' OR data_id='345'... 

2 个答案:

答案 0 :(得分:3)

您的问题需要考虑您所拥有的文件,因为“不同”可能意味着一些不同的事情。请考虑以下示例:

{
    "tripId": 123,
    "thisField": "this",
    "thatField": "that"
},
{
    "tripId": 123,
    "thisField": "other",
    "thatField": "then"
},
{
    "tripId": 345,
    "thisField": "other",
    "thatField": "then"
},
{
    "tripId": 345,
    "thisField": "this",
    "thatField": "that"
},
{
    "tripId": 123,
    "thisField": "this",
    "thatField": "that"
},
{
    "tripId": 789,
    "thisField": "this",
    "thatField": "that"
}

MongoDB有.distinct()方法,该方法会为单个字段返回不同的值,但只有一个字段以及这些项只是作为这些字段值的数组返回。

对于其他任何你想要的.aggregate()方法。这是聚合管道,它具有许多不同的功能,并且由于处理的“管道”特性,可以处理一些非常复杂的操作。

特别是在这里,您可能希望使用$group管道阶段,以便根据键将值“组合”在一起。该“密钥”以_id语句中的$group密钥的形式表示。与SQL中的“SELECT”非常相似,具有“GROUP BY”或“DISTINCT”修饰符(在功能上大致相同),您需要指定结果中所有要包含的字段。

此外,任何未在语句的“GROUP BY”部分中指定的内容都必须经过某种“分组操作”才能选择要显示的字段值。为此,有多种"Group Accumulator Operators"可以对这些值采取行动:

在这种情况下使用$first运算符的一个示例:

db.collection.aggregate([
    { "$match": {
        "tripId": { "$in": [ 123,345 ] }
    }},
    { "$group": {
        "_id": "$tripId",
        "thisField": { "$first": "$thisField" },
        "thatField": { "$first": "$thatField" },
        "total": { "$sum": 1 }
    }}
])

给出了这个结果:

{ "_id" : 345, "thisField" : "other", "thatField" : "then", "total" : 2 }
{ "_id" : 123, "thisField" : "this", "thatField" : "that", "total" : 3 }

因此,通过添加$sum运算符来计算相同的不同值的出现次数,这将选择在分组之外的累加器表达式中提到的指定字段中的值的“第一次”出现键。

在2.6以后的MongoDB版本中,您可以使用$$ROOT表达式变量“快捷”命名您想要的所有字段。这是对文档中存在的“所有”字段的引用,表示当前使用它的状态。写入时间要短一些,但由于语法的原因,输出略有不同:

db.collection.aggregate([
    { "$match": {
        "tripId": { "$in": [ 123,345 ] }
    }},
    { "$group": {
        "_id": "$tripId",
        "doc": { "$first": "$$ROOT" },
        "total": { "$sum": 1 }
    }}
])

输出为:

{
    "_id" : 345,
    "doc" : {
            "_id" : ObjectId("54feaf3839c29b9cd470bcbe"),
            "tripId" : 345,
            "thisField" : "other",
            "thatField" : "then"
    },
    "total" : 2
}
{
    "_id" : 123,
    "doc" : {
            "_id" : ObjectId("54feaf3839c29b9cd470bcbc"),
            "tripId" : 123,
            "thisField" : "this",
            "thatField" : "that"
    },
    "total" : 3
}

这是大多数$group聚合操作的一般情况,您可以在其中指定“键”并将其他字段置于某种“分组运算符”/“累加器”中。

另一种情况是,如果您正在寻找“所有”字段的“不同”出现,那么您可以将这些表示为组表达式的“键”的一部分,如下所示:

db.collection.aggregate([
    { "$match": {
        "tripId": { "$in": [ 123,345 ] }
    }},
    { "$group": {
        "_id": {
            "tripId": "$tripId",
            "thisField": "$thisField",
            "thatField": "$thatField"
        },
        "total": { "$sum": 1 }
    }}
])

这给了我们这个输出:

{
    "_id" : {
            "tripId" : 345,
            "thisField" : "this",
            "thatField" : "that"
    },
    "total" : 1
}
{
    "_id" : {
            "tripId" : 345,
            "thisField" : "other",
            "thatField" : "then"
    },
    "total" : 1
}
{
    "_id" : {
            "tripId" : 123,
            "thisField" : "other",
            "thatField" : "then"
    },
    "total" : 1
}
{
    "_id" : {
            "tripId" : 123,
            "thisField" : "this",
            "thatField" : "that"
    },
    "total" : 2
}

总结果是4个文档,它们考虑作为“复合键”一部分提到的每个字段的“不同”值。它正确地说明了大多数这些组合发生了一次,除了一个实例出现两次且所有相同值的例子。

当然,$$ROOT变量不适用于此处,因为“整个文档”包含每个文档的“唯一”_id字段。您可以随时添加$project阶段来过滤该字段,但是指定所需字段的条件相同:

db.collection.aggregate([
    { "$match": {
        "tripId": { "$in": [ 123,345 ] }
    }},
    { "$project": {
        "_id": 0,
        "tripId": 1,
        "thisField": 1,
        "thatField": 1
    }},
    { "$group": {
        "_id": "$$ROOT",
        "total": { "$sum": 1 }
    }}
])

这是一个介绍,其中包含您可以使用MongoDB以及特别是聚合框架以“不同”查询形式执行的操作的示例。文档中给出了各种其他常见的SQL to Aggregation mapping示例。

另一般情况是您在问题中使用$or。正如您在此处的示例中所看到的,当您希望在相同字段的值上使用相同的“或”条件时,在查询中使用$in运算符的更有效方式。这不是一个“查询文档”数组,而是将“可能的值”数组带到它在表达式中检查的公共字段中。它基本上是一个$or条件,但在这种情况下用较短的形式表示。

答案 1 :(得分:0)

而不是 $或使用 $ in 查询,以满足您的目的。

  

db.collection.find({data_id:{$ in:[123,345,443]}});