【问题标题】:Query documents that have different sub-fields heterogeneous查询具有不同子字段异构的文档
【发布时间】:2014-03-31 11:14:38
【问题描述】:

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

我可以查询以下两种类型的文档,当它是字符串时获取someField作为字符串,如果它有子字段则作为一些子字段? (获取字符串或 all 的子字段很容易)

如果您可以将子字段的格式设置为看起来像单个字符串文档,则可以加分。

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

{
    "_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)

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案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"
            ]}
        }}
    ])
    

    【讨论】:

      【解决方案2】:

      我认为@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 是否存在(未定义为假),然后在必要时进行一些手动字符串连接。

      【讨论】:

      • 您可以随时为您的“真实世界”示例提出另一个问题。如果您正在使用的数据很大,那么您可能希望在不迭代的情况下进行此转换。我一定错过了你想要字符串,所以我也更新了那部分。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-11
      • 2019-07-27
      • 2014-11-23
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      相关资源
      最近更新 更多