Javascript 删除以“名称”开头的所有字段;";
集合中的示例文档:Javascript 删除以“名称”开头的所有字段;";,javascript,mongodb,mongodb-query,Javascript,Mongodb,Mongodb Query,集合中的示例文档: {“teamAlpha”:{},“teamBeta”:{},“leader_name”:“leader”} 对于这样的文档,我想删除所有以“team”开头的字段。因此,预期的结果是 {leader_name:“leader”} 我目前正在使用一个函数: db.teamList.find().forEach( function(document) { for(var k in document) { if (k.startsWit
{“teamAlpha”:{},“teamBeta”:{},“leader_name”:“leader”}
对于这样的文档,我想删除所有以“team”
开头的字段。因此,预期的结果是
{leader_name:“leader”}
我目前正在使用一个函数:
db.teamList.find().forEach(
function(document) {
for(var k in document) {
if (k.startsWith('team')) {
delete document[k];
}
}
db.teamList.save(document);
}
);
我想知道是否有更好的方法解决这个问题。最好是事先确定所有可能的密钥,然后发布一个更新来删除所有密钥。根据可用的MongoDB版本,将有不同的方法
MongoDB 3.4:$objectToArray
.aggregate()
语句通过$objectToArray
将文档中的字段转换为数组,然后仅应用于返回“key”的前四个字母与字符串匹配的字段“team”
。然后使用和进行处理,以生成匹配字段的“唯一列表”
后续指令仅将游标中返回的列表处理为单个对象,如:
{
"teamBeta" : "",
"teamAlpha" : ""
}
然后将其传递给以从所有文档中删除这些字段
早期版本:mapReduce
相同的基本问题,其中唯一的区别是,where不存在一种方法,我们只需使用调用来应用于所有匹配的文档。这就是新的API调用实际上所做的一切
除了这些选择之外
当然,仅仅为了删除字段而迭代所有文档是不明智的,因此上述任何一种方法都是“首选”方法。唯一可能的失败是构造键的“不同列表”实际上超过了16MB BSON限制。这是非常极端的,但根据实际数据,这是可能的
因此,本质上有“两个扩展”自然适用于这些技术:
.aggregate()一起使用
var fields = [];
db.teamList.aggregate([
{ "$project": {
"_id": 0,
"fields": {
"$map": {
"input": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"as": "d",
"cond": { "$eq": [{ "$substrCP": [ "$$d.k", 0, 4 ] }, "team" ] }
}
},
"as": "f",
"in": "$$f.k"
}
}
}},
{ "$unwind": "$fields" },
{ "$group": { "_id": "$fields" } }
]).forEach( d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
});
if ( fields.length > 0 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
db.teamList.mapReduce(
function() {
Object.keys(this).filter( k => /^team/.test(k) )
.forEach( k => emit(k,1) );
},
function() {},
{ "out": { "replace": "tempoutput" } }
);
db.tempoutput.find({},{ "_id": 1 }).forEach(d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
});
if ( fields.length > 0 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
这实际上是将“游标”上处理的字段数“成批”为2000个,作为请求,“应”保持在16MB BSON限制之下mapReduce()的临时集合
var fields = [];
db.teamList.aggregate([
{ "$project": {
"_id": 0,
"fields": {
"$map": {
"input": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"as": "d",
"cond": { "$eq": [{ "$substrCP": [ "$$d.k", 0, 4 ] }, "team" ] }
}
},
"as": "f",
"in": "$$f.k"
}
}
}},
{ "$unwind": "$fields" },
{ "$group": { "_id": "$fields" } }
]).forEach( d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
});
if ( fields.length > 0 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
db.teamList.mapReduce(
function() {
Object.keys(this).filter( k => /^team/.test(k) )
.forEach( k => emit(k,1) );
},
function() {},
{ "out": { "replace": "tempoutput" } }
);
db.tempoutput.find({},{ "_id": 1 }).forEach(d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
});
if ( fields.length > 0 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
在本质上也是相同的过程的情况下,除了mapReduce
无法输出到“游标”之外,您需要输出到仅包含“不同字段名”的临时集合,然后从该集合中迭代游标,以便以相同的“批处理”方式进行处理db.teamList.update({},{ "$unset": { "teamBeta": "", "teamAlpha": "" } },{ "multi": true })
这是非常有效的,因为所有其他语句都在计算这些名称应该适合您。最好是事先确定所有可能的键,然后发布一个更新以删除所有键。根据可用的MongoDB版本,将有不同的方法
MongoDB 3.4:$objectToArray
.aggregate()
语句通过$objectToArray
将文档中的字段转换为数组,然后仅应用于返回“key”的前四个字母与字符串匹配的字段“team”
。然后使用和进行处理,以生成匹配字段的“唯一列表”
后续指令仅将游标中返回的列表处理为单个对象,如:
{
"teamBeta" : "",
"teamAlpha" : ""
}
然后将其传递给以从所有文档中删除这些字段
早期版本:mapReduce
相同的基本问题,其中唯一的区别是,where不存在一种方法,我们只需使用调用来应用于所有匹配的文档。这就是新的API调用实际上所做的一切
除了这些选择之外
当然,仅仅为了删除字段而迭代所有文档是不明智的,因此上述任何一种方法都是“首选”方法。唯一可能的失败是构造键的“不同列表”实际上超过了16MB BSON限制。这是非常极端的,但根据实际数据,这是可能的
因此,本质上有“两个扩展”自然适用于这些技术:
.aggregate()一起使用
var fields = [];
db.teamList.aggregate([
{ "$project": {
"_id": 0,
"fields": {
"$map": {
"input": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"as": "d",
"cond": { "$eq": [{ "$substrCP": [ "$$d.k", 0, 4 ] }, "team" ] }
}
},
"as": "f",
"in": "$$f.k"
}
}
}},
{ "$unwind": "$fields" },
{ "$group": { "_id": "$fields" } }
]).forEach( d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
});
if ( fields.length > 0 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
db.teamList.mapReduce(
function() {
Object.keys(this).filter( k => /^team/.test(k) )
.forEach( k => emit(k,1) );
},
function() {},
{ "out": { "replace": "tempoutput" } }
);
db.tempoutput.find({},{ "_id": 1 }).forEach(d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
});
if ( fields.length > 0 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
这实际上是将“游标”上处理的字段数“成批”为2000个,作为请求,“应”保持在16MB BSON限制之下mapReduce()的临时集合
var fields = [];
db.teamList.aggregate([
{ "$project": {
"_id": 0,
"fields": {
"$map": {
"input": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"as": "d",
"cond": { "$eq": [{ "$substrCP": [ "$$d.k", 0, 4 ] }, "team" ] }
}
},
"as": "f",
"in": "$$f.k"
}
}
}},
{ "$unwind": "$fields" },
{ "$group": { "_id": "$fields" } }
]).forEach( d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
});
if ( fields.length > 0 ) {
db.teamList.updateMany({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
}
);
}
db.teamList.mapReduce(
function() {
Object.keys(this).filter( k => /^team/.test(k) )
.forEach( k => emit(k,1) );
},
function() {},
{ "out": { "replace": "tempoutput" } }
);
db.tempoutput.find({},{ "_id": 1 }).forEach(d => {
fields.push(d._id);
if ( fields.length >= 2000 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
});
if ( fields.length > 0 ) {
db.teamList.update({},
{ "$unset":
fields.reduce((acc,curr) => Object.assign(acc,{ [curr]: "" }),{})
},
{ "multi": true }
);
}
在本质上也是相同的过程的情况下,除了mapReduce
无法输出到“游标”之外,您需要输出到仅包含“不同字段名”的临时集合,然后从该集合中迭代游标,以便以相同的“批处理”方式进行处理