查询具有不同子字段异构的文档

时间:2014-03-31 11:14:38

标签: mongodb mongodb-query aggregation-framework

我有一个包含两个不同(但相似)结构的文档的集合,一些包含字段“someField”和一个字符串值,另一些包含字段“someField”和一堆子字段。

我可以查询以下两种类型的文档,当它是字符串时将someField作为字符串,如果它有子字段,可以作为某些子字段吗? (很容易得到字符串或所有子字段)

如果您可以将子字段格式化为单个字符串文档,则获得奖励。

包含两种类型文档的集合(简化示例)

{
    "_id" : ObjectId("53345585cdf2fb6a03f4a7bc"),
    "document" : {
        "someField" : "Foo 1, Bar 2",
    }
}
{
    "_id" : ObjectId("533455sdfghjfb6a03f4a7bc"),
    "document" : {
        "someField" : {
            "foo": "1",
            "bar": "2",
            "wibble": "I don't want this field"
        }
    }
}

额外信息:

我到目前为止最好的方法是使用两个查询,然后在另一个脚本或代码中将结果连接在一起:

db.someCollection.find(
    {
        "document.someField.foo":{$exists:false},
    },
    {
        "document.someField": 1,
        _id: 0 
    }
).forEach(printjson)

db.someCollection.find(
    {
        "document.someField.foo":{$exists:true},
    },
    {
        "document.someField.foo": 1,
        "document.someField.bar": 1,
        _id: 0 
    }
).forEach(printjson)

2 个答案:

答案 0 :(得分:1)

您的问题有点抽象,但您可以使用.aggregate()$project运算符来处理此类解决方案:

db.collection.aggregate([
    { "$project": {
        "onefield": { "$cond": [
            "$document.someField.foo",
            {
                "foo": "$document.someField.foo",
                "bar": "$document.someField.bar"
            },
            "$document.someField"
        ]}
    }}
])

这也使用了三元$cond运算符,以便评估"结果如何。

因此,如果您的商品执行包含子文档字段,那么您可以重新塑造"到你想要的领域。当他们时,您可以按照(如果您的逻辑需要)展示字段,再嵌套$cond操作以确定如何处理该领域。

当然,如果您真的希望所有内容都是字符串,那么请使用$concat代替:

db.collection.aggregate([
    { "$project": {
        "onefield": { "$cond": [
            "$document.someField.foo",
            { "$concat": [
                "Foo ",
                "$document.someField.foo",
                " ,Bar ",
                "$document.someField.bar"
            ]},
            "$document.someField"
        ]}
    }}
])

答案 1 :(得分:0)

我认为@Neil-Lunn's answer可能更好(我仍在努力将其转换为我的真实世界示例),但我设法使用JS函数自己完成。 *简化了我的真实世界,因此可能包含拼写错误。

db.someCollection.find()
    .forEach(function(o) {
        if(o.document.someField.foo) {
            print("Foo " 
                + o.document.someField.foo 
                + ", Bar "
                + o.document.someField.bar
            );
        } else {
            print(o.document.someField);
        }
    }
)

条件检查foo是否存在(undefined为false),然后在必要时进行一些手动字符串连接。