【问题标题】:Omit empty fields from MongoDB query result从 MongoDB 查询结果中省略空字段
【发布时间】:2021-12-08 21:52:30
【问题描述】:

有没有办法从 MongoDB 查询结果的文档(查找或聚合)中省略空字段(例如空字符串或空数组)。

数据库中的文档:

{
    "_id" : ObjectId("5dc3fcb388c1c7c5620ed496"),
    "name": "Bill",
    "emptyString" : "",
    "emptyArray" : []
}

输出:

{
    "_id" : ObjectId("5dc3fcb388c1c7c5620ed496"),
    "name": "Bill"
}

Elasticsearch 的类似问题:Omit null fields from elasticsearch results

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    请使用聚合函数。 如果要删除密钥。您通过使用 $project 来使用 $cond。

    db.Speed.aggregate( [
       {
          $project: {
             name: 1,
             "_id": 1,
             "emptyString": {
                $cond: {
                   if: { $eq: [ "", "$emptyString" ] },
                   then: "$$REMOVE",
                   else: "$emptyString"
                }
             },
             "emptyArray": {
                $cond: {
                   if: { $eq: [ [], "$emptyArray" ] },
                   then: "$$REMOVE",
                   else: "$emptyArray"
                }
             }
          }
       }
    ] )
    

    【讨论】:

    • 这提供了一些见解。谢谢!是否可以一次对所有字段执行此操作,而不是为每个字段编写冗余代码。
    • 谢谢。这帮助了我。
    【解决方案2】:

    可以做到这一点的一种方法是使用cursor.map()find()aggregation([]) 两者都可用。

    想法是列出文档中存在/可能存在的字段,并使用delete 运算符过滤掉字段(它们是空字符串或空数组,两者都有@987654327 @property) 来自返回的文档。

    Mongo Shell:

    var fieldsList = ["name", "emptyString", "emptyArray"];
    
    db.collection.find().map(function(d) {
      fieldsList.forEach(function(k) {
        if (
          k in d &&
          (Array.isArray(d[k]) ||
            (typeof d[k] === "string" || d[k] instanceof String)) &&
          d[k].length === 0
        ) {
          delete d[k];
        }
      });
      return d;
    });
    

    测试文档:

    {
      "_id" : ObjectId("5dc426d1f667120607ac5006"),
      "name" : "Bill",
      "emptyString" : "",
      "emptyArray" : [ ]
    }
    {
      "_id" : ObjectId("5dc426d1f667120607ac5007"),
      "name" : "Foo",
      "emptyString" : "foo",
      "emptyArray" : [ ]
    }
    {
      "_id" : ObjectId("5dc426d1f667120607ac5008"),
      "name" : "Bar",
      "emptyString" : "",
      "emptyArray" : [
              "foo",
              "bar"
      ]
    }
    {
      "_id" : ObjectId("5dc426d1f667120607ac5009"),
      "name" : "May",
      "emptyString" : "foobar",
      "emptyArray" : [
              "foo",
              "bar"
      ]
    }
    

    O/P

    [
            {
                    "_id" : ObjectId("5dc426d1f667120607ac5006"),
                    "name" : "Bill"
            },
            {
                    "_id" : ObjectId("5dc426d1f667120607ac5007"),
                    "name" : "Foo",
                    "emptyString" : "foo"
            },
            {
                    "_id" : ObjectId("5dc426d1f667120607ac5008"),
                    "name" : "Bar",
                    "emptyArray" : [
                            "foo",
                            "bar"
                    ]
            },
            {
                    "_id" : ObjectId("5dc426d1f667120607ac5009"),
                    "name" : "May",
                    "emptyString" : "foobar",
                    "emptyArray" : [
                            "foo",
                            "bar"
                    ]
            }
    ]
    

    注意:如果文档中的字段数量非常大,这可能不是非常理想的解决方案,因为比较将针对文档中的所有字段进行。您可能希望将 fieldsList 与怀疑为空数组或字符串的属性分块。

    【讨论】:

      【解决方案3】:

      我认为从输出中删除所有空字符串和空数组字段的最简单方法是在下面添加聚合阶段。 (是的,“简单”是相对的,当你必须创建这些级别的逻辑来完成这样一个微不足道的任务时......)

      $replaceRoot: {
        newRoot: {
          $arrayToObject: {
            $filter: {
              input: {
                $objectToArray: '$$ROOT'
              },
              as: 'item',
              cond: {
                $and: [
                  { $ne: [ '$$item.v', [] ] },
                  { $ne: [ '$$item.v', '' ] }
                ]
              }
            }
          }
        }
      }
      

      只需修改 cond 子句以过滤掉其他类型的字段(例如null)。

      顺便说一句:我还没有测试过它的性能,但至少它是通用的并且有些可读性。

      编辑:重要! $replaceRoot-stage 确实会阻止 MongoDB 优化管道,因此如果您在运行 .find() 的视图中使用它,它将附加一个 $match -stage 到视图管道的末尾,而不是在管道的开头预先进行索引搜索。这将对性能产生重大影响。不过,您可以在自定义管道中安全地使用它,只要在它之前有 $match-stage 即可。 (至少就我有限的 MongoDB 知识而言)。如果有人知道如何在查询时将 $match-stage 附加到视图中,请发表评论:-)

      【讨论】:

        猜你喜欢
        • 2019-12-12
        • 1970-01-01
        • 1970-01-01
        • 2015-02-07
        • 2020-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多