MongoDb - 删除所有空字段

Til*_*ann 8 null mongodb

简短的问题

如何删除null给定MongoDb集合的所有文档中的所有字段?

背景

我有一个存储在MongoDb数据库中的JSON文档集合,其中每个文档都是表单

{
    'property1': 'value1',
    'property2': 'value2',
    ...
}
Run Code Online (Sandbox Code Playgroud)

但每个文档可能有一个null条目而不是值条目.我想通过删除所有条目来节省磁盘空间null.null在我的情况下,条目的存在不包含任何信息,因为我先验地知道JSON文档的格式.

小智 10

// run in mongo shell  

var coll = db.getCollection("collectionName");
var cursor = coll.find();
while (cursor.hasNext()) {
    var doc = cursor.next();
    var keys = {};
    var hasNull = false;
    for ( var x in doc) {
        if (x != "_id" && doc[x] == null) {
            keys[x] = 1;
            hasNull = true;
        }
    }
    if (hasNull) {
        coll.update({_id: doc._id}, {$unset:keys});
    }
}
Run Code Online (Sandbox Code Playgroud)


Xav*_*hot 5

开始Mongo 4.2db.collection.update()可以接受聚合管道,最后允许根据其值删除字段:

// { _id: ObjectId("5d0e8...d2"), property1: "value1", property2: "value2" }
// { _id: ObjectId("5d0e8...d3"), property1: "value1", property2: null, property3: "value3" }
db.collection.update(
  {},
  [{ $replaceWith: {
    $arrayToObject: {
      $filter: {
        input: { $objectToArray: "$$ROOT" },
        as: "item",
        cond: { $ne: ["$$item.v", null] }
      }
    }
  }}],
  { multi: true }
)
// { _id: ObjectId("5d0e8...d2"), property1: "value1", property2: "value2" }
// { _id: ObjectId("5d0e8...d3"), property1: "value1", property3: "value3" }
Run Code Online (Sandbox Code Playgroud)

详细说明:

  • 第一部分{}是匹配查询,过滤要更新的文档(在我们的例子中是所有文档)。

  • 第二部分[{ $replaceWith: { ... }]是更新聚合管道(注意方括号表示使用聚合管道):

    • 使用$objectToArray,我们首先将文档转换为键/值数组,例如[{ k: "property1", v: "value1" }, { k: "property2", v: null }, ...]
    • $filter,我们通过除去物品,其过滤此数组的键/值vnull
    • 然后我们使用 将过滤后的键/值数组转换回一个对象$arrayToObject
    • 最后,我们用修改后的文档替换整个文档$replaceWith
  • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。

  • 这应该是公认的答案。它与结构无关,只需替换集合名称即可工作。唯一需要注意的是,它仅适用于顶级键,而不适用于嵌套键(如果有)。 (2认同)