Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
查找并更改mongodb集合中的所有日期类型字段_Mongodb_Mongodb Query_Mongo Shell_Mongodb Shell - Fatal编程技术网

查找并更改mongodb集合中的所有日期类型字段

查找并更改mongodb集合中的所有日期类型字段,mongodb,mongodb-query,mongo-shell,mongodb-shell,Mongodb,Mongodb Query,Mongo Shell,Mongodb Shell,我有一个包含多个日期类型字段的集合。我知道我可以根据它们的键来更改它们,但是有没有办法找到所有以日期为类型的字段,并在一个脚本中更改所有字段 更新 非常感谢chridam帮了我的忙。根据他的代码,我想出了这个解决方案。(注意:我有Mongo3.2.9,chridam答案中的一些代码片段无法运行。它可能有效,但对我来说不起作用。) map=function(){ 对于(此中的var键){ 如果(key!=null&&this[key]!=null&&this[key]instanceof Date

我有一个包含多个日期类型字段的集合。我知道我可以根据它们的键来更改它们,但是有没有办法找到所有以日期为类型的字段,并在一个脚本中更改所有字段

更新

非常感谢chridam帮了我的忙。根据他的代码,我想出了这个解决方案。(注意:我有Mongo3.2.9,chridam答案中的一些代码片段无法运行。它可能有效,但对我来说不起作用。)

map=function(){
对于(此中的var键){
如果(key!=null&&this[key]!=null&&this[key]instanceof Date){
emit(key,null);
}
}
}
collectionName=“testcollection\u copy”;
mr=db.runCommand({
“mapreduce”:collectionName,
“地图”:地图,
“reduce”:函数(){},
“out”:“map\u reduce\u test”//out是必需的
}) 
dateFields=db[mr.result].distinct(“\u id”)
printjson(日期字段)
//更新文件
db[collectionName].find().forEach(函数(文档){

对于(var i=0;i这样的操作将涉及两个任务;一个是通过获取日期类型的字段列表,另一个是通过聚合或写入操作更新集合

NB:以下方法假定所有日期字段都位于文档的根级别,而不是嵌入或子文档

MapReduce

您需要做的第一件事是运行以下操作。这将帮助您确定集合中每个文档的每个属性是否为日期类型,并返回不同的日期字段列表:

// define helper function to determine if a key is of Date type
isDate = function(dt) {
    return dt && dt instanceof Date && !isNaN(dt.valueOf());
}

// map function
map = function() {
    for (var key in this) { 
        if (isDate(value[key]) 
            emit(key, null); 
    }
}

// variable with collection name
collectionName = "yourCollectionName";

mr = db.runCommand({
    "mapreduce": collectionName,
    "map": map,  
    "reduce": function() {}
}) 

dateFields = db[mr.result].distinct("_id")
printjson(dateFields)

//output: [ "validFrom", "validTo", "registerDate"" ]
选项1:通过聚合框架更新集合

您可以使用聚合框架来更新集合,特别是MongoDB 3.4版及更高版本中可用的操作符。如果您的MongoDB服务器版本不支持此操作,您可以使用其他解决方法更新集合(如下一选项所述)

时间戳是通过使用算术聚合运算符计算的,日期字段为分钟,日期自历元
新日期(“1970-01-01”)
为子日期

聚合管道的结果文档然后通过操作符写入同一集合,从而使用新字段更新集合

本质上,您希望最终运行以下聚合管道,该管道使用上述算法将日期字段转换为时间戳:

pipeline = [
    {
        "$addFields": {
            "validFrom": { "$subtract": [ "$validFrom", new Date("1970-01-01") ] },
            "validTo": { "$subtract": [ "$validTo", new Date("1970-01-01") ] },
            "registerDate": { "$subtract": [ "$registerDate", new Date("1970-01-01") ] }
        }
    },
    { "$out": collectionName }
]
db[collectionName].aggregate(pipeline)
您可以根据日期字段列表动态创建上述管道数组,如下所示:

var addFields = { "$addFields": { } },
    output = { "$out": collectionName };

dateFields.forEach(function(key){
    var subtr = ["$"+key, new Date("1970-01-01")];
    addFields["$addFields"][key] = { "$subtract": subtr };
});

db[collectionName].aggregate([addFields, output])
选项2:通过批量更新集合

由于此选项是不支持上面的运算符时的一种解决方法,因此可以使用管道使用相同的实现创建新的时间戳字段,但不必将结果写入同一集合,而是可以使用方法从聚合结果中删除对于每个文档,使用方法更新集合

以下示例显示了此方法:

ops = []
pipeline = [
    {
        "$project": {
            "validFrom": { "$subtract": [ "$validFrom", new Date("1970-01-01") ] },
            "validTo": { "$subtract": [ "$validTo", new Date("1970-01-01") ] },
            "registerDate": { "$subtract": [ "$registerDate", new Date("1970-01-01") ] }
        }
    }
]

db[collectionName].aggregate(pipeline).forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { 
                    "validFrom": doc.validFrom,
                    "validTo": doc.validTo,
                    "registerDate": doc.registerDate
                }
            }
        }
    });

    if (ops.length === 500 ) {
        db[collectionName].bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db[collectionName].bulkWrite(ops);
使用与上面选项1相同的方法动态创建管道和批量方法对象:

var ops = [],
    project = { "$project": { } },

dateFields.forEach(function(key){
    var subtr = ["$"+key, new Date("1970-01-01")];
    project["$project"][key] = { "$subtract": subtr };
});

setDocFields = function(doc, keysList) { 
    setObj = { "$set": { } };
    return keysList.reduce(function(obj, key) {  
        obj["$set"][key] = doc[key];
        return obj;
    }, setObj )
}

db[collectionName].aggregate([project]).forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": setDocFields(doc, dateFields)
        }
    });

    if (ops.length === 500 ) {
        db[collectionName].bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db[collectionName].bulkWrite(ops);

这样的操作将涉及两个任务:一个是通过获取日期类型的字段列表,另一个是通过聚合或写入操作更新集合

NB:以下方法假定所有日期字段都位于文档的根级别,而不是嵌入或子文档

MapReduce

您需要做的第一件事是运行以下操作。这将帮助您确定集合中每个文档的每个属性是否为日期类型,并返回不同的日期字段列表:

// define helper function to determine if a key is of Date type
isDate = function(dt) {
    return dt && dt instanceof Date && !isNaN(dt.valueOf());
}

// map function
map = function() {
    for (var key in this) { 
        if (isDate(value[key]) 
            emit(key, null); 
    }
}

// variable with collection name
collectionName = "yourCollectionName";

mr = db.runCommand({
    "mapreduce": collectionName,
    "map": map,  
    "reduce": function() {}
}) 

dateFields = db[mr.result].distinct("_id")
printjson(dateFields)

//output: [ "validFrom", "validTo", "registerDate"" ]
选项1:通过聚合框架更新集合

您可以使用聚合框架来更新集合,特别是MongoDB 3.4版及更高版本中可用的操作符。如果您的MongoDB服务器版本不支持此操作,您可以使用其他解决方法更新集合(如下一选项所述)

时间戳是通过使用算术聚合运算符计算的,日期字段为分钟,日期自历元
新日期(“1970-01-01”)
为子日期

聚合管道的结果文档然后通过操作符写入同一集合,从而使用新字段更新集合

本质上,您希望最终运行以下聚合管道,该管道使用上述算法将日期字段转换为时间戳:

pipeline = [
    {
        "$addFields": {
            "validFrom": { "$subtract": [ "$validFrom", new Date("1970-01-01") ] },
            "validTo": { "$subtract": [ "$validTo", new Date("1970-01-01") ] },
            "registerDate": { "$subtract": [ "$registerDate", new Date("1970-01-01") ] }
        }
    },
    { "$out": collectionName }
]
db[collectionName].aggregate(pipeline)
您可以根据日期字段列表动态创建上述管道数组,如下所示:

var addFields = { "$addFields": { } },
    output = { "$out": collectionName };

dateFields.forEach(function(key){
    var subtr = ["$"+key, new Date("1970-01-01")];
    addFields["$addFields"][key] = { "$subtract": subtr };
});

db[collectionName].aggregate([addFields, output])
选项2:通过批量更新集合

由于此选项是不支持上面的运算符时的一种解决方法,因此可以使用管道使用相同的实现创建新的时间戳字段,但不必将结果写入同一集合,而是可以使用方法从聚合结果中删除对于每个文档,使用方法更新集合

以下示例显示了此方法:

ops = []
pipeline = [
    {
        "$project": {
            "validFrom": { "$subtract": [ "$validFrom", new Date("1970-01-01") ] },
            "validTo": { "$subtract": [ "$validTo", new Date("1970-01-01") ] },
            "registerDate": { "$subtract": [ "$registerDate", new Date("1970-01-01") ] }
        }
    }
]

db[collectionName].aggregate(pipeline).forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { 
                    "validFrom": doc.validFrom,
                    "validTo": doc.validTo,
                    "registerDate": doc.registerDate
                }
            }
        }
    });

    if (ops.length === 500 ) {
        db[collectionName].bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db[collectionName].bulkWrite(ops);
使用与上面选项1相同的方法动态创建管道和批量方法对象:

var ops = [],
    project = { "$project": { } },

dateFields.forEach(function(key){
    var subtr = ["$"+key, new Date("1970-01-01")];
    project["$project"][key] = { "$subtract": subtr };
});

setDocFields = function(doc, keysList) { 
    setObj = { "$set": { } };
    return keysList.reduce(function(obj, key) {  
        obj["$set"][key] = doc[key];
        return obj;
    }, setObj )
}

db[collectionName].aggregate([project]).forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": setDocFields(doc, dateFields)
        }
    });

    if (ops.length === 500 ) {
        db[collectionName].bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db[collectionName].bulkWrite(ops);

你能举个例子吗?@chridam是的,当然。想象一个集合包含如下字段:loginName(字符串)、password(字符串)、validFrom(日期)、validTo(日期)、registerDate(日期)。我想编写一个脚本来查找al