Mongodb 删除所有空字段
如何从给定集合的所有文档中删除Mongodb 删除所有空字段,mongodb,null,Mongodb,Null,如何从给定集合的所有文档中删除null的所有字段 我有一系列文件,如: { 'property1': 'value1', 'property2': 'value2', ... } 但是每个文档可能有一个null条目,而不是一个值条目 我想通过删除所有null条目来删除。在我的例子中,null条目的存在不包含任何信息,因为我事先知道JSON文档的格式。//在mongo shell中运行 var coll=db.getCollection(“collectionName”
null
的所有字段
我有一系列文件,如:
{
'property1': 'value1',
'property2': 'value2',
...
}
但是每个文档可能有一个null
条目,而不是一个值条目
我想通过删除所有null
条目来删除。在我的例子中,null
条目的存在不包含任何信息,因为我事先知道JSON文档的格式。//在mongo shell中运行
var coll=db.getCollection(“collectionName”);
var cursor=coll.find();
while(cursor.hasNext()){
var doc=cursor.next();
var键={};
var hasNull=false;
用于(单据中的var x){
如果(x!=“_id”&&doc[x]==null){
键[x]=1;
hasNull=true;
}
}
if(hasNull){
coll.update({u id:doc.{u id},{$unset:keys});
}
}
像上面提到的这个问题():
不幸的是,MongoDB不支持任何查询具有特定值的所有字段的方法
因此,您可以迭代文档(如向导的示例)或以非mongodb的方式进行
如果这是一个JSON文件,请删除sed中null
的所有行:
sed '/null/d' ./mydata.json
您可以使用mongoupdateMany功能,但必须指定要更新的参数,例如
year
参数:
db.collection.updateMany({year: null}, { $unset : { year : 1 }})
这是一个重要的问题,因为mongodb无法索引空值(即不要查询空值,否则您将等待很长时间),所以最好完全避免空值,并使用
setOnInsert
设置默认值
下面是一个删除空值的递归解决方案:
/**
* RETRIEVES A LIST OF ALL THE KEYS IN A DOCUMENT, WHERE THE VALUE IS 'NULL' OR 'UNDEFINED'
*
* @param doc
* @param keyName
* @param nullKeys
*/
function getNullKeysRecursively(doc, keyName, nullKeys)
{
for (var item_property in doc)
{
// SKIP BASE-CLASS STUFF
if (!doc.hasOwnProperty(item_property))
continue;
// SKIP ID FIELD
if (item_property === "_id")
continue;
// FULL KEY NAME (FOR SUB-DOCUMENTS)
var fullKeyName;
if (keyName)
fullKeyName = keyName + "." + item_property;
else
fullKeyName = item_property;
// DEBUGGING
// print("fullKeyName: " + fullKeyName);
// NULL FIELDS - MODIFY THIS BLOCK TO ADD CONSTRAINTS
if (doc[item_property] === null || doc[item_property] === undefined)
nullKeys[fullKeyName] = 1;
// RECURSE OBJECTS / ARRAYS
else if (doc[item_property] instanceof Object || doc[item_property] instanceof Array)
getNullKeysRecursively(doc[item_property], fullKeyName, nullKeys);
}
}
/**
* REMOVES ALL PROPERTIES WITH A VALUE OF 'NULL' OR 'UNDEFINED'.
* TUNE THE 'LIMIT' VARIABLE TO YOUR MEMORY AVAILABILITY.
* ONLY CLEANS DOCUMENTS THAT REQUIRE CLEANING, FOR EFFICIENCY.
* USES bulkWrite FOR EFFICIENCY.
*
* @param collectionName
*/
function removeNulls(collectionName)
{
var coll = db.getCollection(collectionName);
var lastId = ObjectId("000000000000000000000000");
var LIMIT = 10000;
while (true)
{
// GET THE NEXT PAGE OF DOCUMENTS
var page = coll.find({ _id: { $gt: lastId } }).limit(LIMIT);
if (! page.hasNext())
break;
// BUILD BULK OPERATION
var arrBulkOps = [];
page.forEach(function(item_doc)
{
lastId = item_doc._id;
var nullKeys = {};
getNullKeysRecursively(item_doc, null, nullKeys);
// ONLY UPDATE MODIFIED DOCUMENTS
if (Object.keys(nullKeys).length > 0)
// UNSET INDIVIDUAL FIELDS, RATHER THAN REWRITE THE ENTIRE DOC
arrBulkOps.push(
{ updateOne: {
"filter": { _id: item_doc._id },
"update": { $unset: nullKeys }
} }
);
});
coll.bulkWrite(arrBulkOps, { ordered: false } );
}
}
// GO GO GO
removeNulls('my_collection');
在以下日期之前提交文件:
{
"_id": ObjectId("5a53ed8f6f7c4d95579cb87c"),
"first_name": null,
"last_name": "smith",
"features": {
"first": {
"a": 1,
"b": 2,
"c": null
},
"second": null,
"third" : {},
"fourth" : []
},
"other": [
null,
123,
{
"a": 1,
"b": "hey",
"c": null
}
]
}
在下列日期后提交文件:
{
"_id" : ObjectId("5a53ed8f6f7c4d95579cb87c"),
"last_name" : "smith",
"features" : {
"first" : {
"a" : 1,
"b" : 2
}
},
"other" : [
null,
123,
{
"a" : 1,
"b" : "hey"
}
]
}
如您所见,它删除了null
、未定义的、空对象和空数组。如果需要增加/减少攻击性,则需要修改块“空字段-修改此块以添加约束”
欢迎编辑,特别是@stennie开始Mongo 4.2
,可以接受聚合管道,最终允许基于其值删除字段:
// { _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" }
详情如下:
- 第一部分是匹配查询,过滤要更新的文档(在本例中是所有文档)
- 第二部分是更新聚合管道(注意方括号表示使用聚合管道):
- 使用,我们首先将文档转换为键/值数组,例如
[{k:“property1”,v:“value1”},{k:“property2”,v:null},…]
- 使用,我们通过删除
v
为null
的项来过滤这个键值数组
- 然后,我们使用将经过过滤的键值数组转换回一个对象
- 最后,我们用修改后的文档替换整个文档
- 不要忘记
{multi:true}
,否则只会更新第一个匹配的文档
此答案很有用,但不会取消子文档空成员的设置