gpt4 book ai didi

javascript - 删除所有以名称 "XX"开头的字段

转载 作者:行者123 更新时间:2023-11-28 04:20:38 24 4
gpt4 key购买 nike

集合中的示例文档:

{ "teamAlpha": { }, "teamBeta": { }, "leader_name": "leader"}

对于此类文档,我想删除所有以 "team" 开头的字段。所以预期的结果是

{leader_name: "领导者"}

我当前正在使用一个函数:

db.teamList.find().forEach(
function(document) {
for(var k in document) {
if (k.startsWith('team')) {
delete document[k];
}
}
db.teamList.save(document);
}
);

我想知道是否有更好的方法来解决这个问题。

最佳答案

提前确定所有可能的键然后发出单个 "multi" 会“更好”更新以删除所有 key 。根据可用的 MongoDB 版本,会有不同的方法。

MongoDB 3.4:$objectToArray
let 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" } }
])
.map( d => ({ [d._id]: "" }))
.reduce((acc,curr) => Object.assign(acc,curr),{})

db.teamList.updateMany({},{ "$unset": fields });

.aggregate() 语句通过 $objectToArray 将文档中的字段转换为数组,然后应用 $filter仅返回“key”的前四个字母与字符串“team”匹配的内容。然后用 $unwind 进行处理和 $group制作匹配字段的“唯一列表”。

后续指令仅将游标中返回的列表处理为单个对象,例如:

{
"teamBeta" : "",
"teamAlpha" : ""
}

然后将其传递给 $unset从所有文档中删除这些字段。

早期版本:mapReduce

var fields = db.teamList.mapReduce(
function() {
Object.keys(this).filter( k => /^team/.test(k) )
.forEach( k => emit(k,1) );
},
function() {},
{ "out": { "inline": 1 } }
)
.results.map( d => ({ [d._id]: "" }))
.reduce((acc,curr) => Object.assign(acc,curr),{})

db.teamList.update({},{ "$unset": fields },{ "multi": true });

基本相同,唯一的区别在于 .updateMany()不存在作为我们简单调用 .update() 的方法使用"multi" parameter应用于所有匹配的文档。这就是新 API 调用实际执行的全部操作。

超越这些选项

仅仅为了删除字段而迭代所有文档当然是不明智的,因此上述任一方法都是“首选”方法。唯一可能的失败是构建 key 的“不同列表”实际上超出了 16MB BSON 限制。这是相当极端的,但根据实际数据,这是可能的。

因此,本质上有“两个扩展”自然适用于这些技术:

  1. 将“光标”与.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]: "" }),{})
    }
    );
    }

    这实际上会将“光标”上处理的字段数量“批处理”为 2000 个,这“应该”远低于请求的 16MB BSON 限制。

  2. 通过 mapReduce() 使用临时集合

    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 无法输出到“光标”,您需要输出到仅包含“不同字段名称”的临时集合,然后进行迭代该集合中的光标,以便以相同的“批处理”方式进行处理。

正如类似的初始方法一样,这些选项比迭代整个集合并单独对每个文档进行调整要高效得多。通常没有必要这样做,因为任何“不同列表”实际上导致单个更新请求超过 16MB 的可能性确实非常大。但这将再次成为处理这种极端情况的“首选”方式。

一般

当然,如果您只是知道所有字段名称,并且不需要通过检查集合来计算出它们,那么只需用已知名称编写语句即可:

db.teamList.update({},{ "$unset": { "teamBeta": "", "teamAlpha": "" } },{ "multi": true })

这是完全有效的,因为所有其他语句正在做的就是计算出这些名称应该适合您。

关于javascript - 删除所有以名称 "XX"开头的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45472583/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com