web-dev-qa-db-fra.com

Conversion de chaîne en date dans mongodb

Est-il possible de convertir une chaîne en date à l'aide d'un format personnalisé à l'aide de mongodb Shell

J'essaie de convertir "21/May/2012: 16: 35: 33 -0400" à ce jour,

Est-il possible de passer DateFormatter ou quelque chose à la méthode Date.parse(...) ou ISODate(....)?

22
user883257

Vous pouvez utiliser le javascript du deuxième lien fourni par Ravi Khakhkhar ou vous devrez effectuer une manipulation de chaîne pour convertir votre chaîne d'origine (certains des caractères spéciaux de votre format original ne sont pas reconnus comme des délimètres valides) une fois que vous faites cela, vous pouvez utiliser "nouveau" 

training:PRIMARY> Date()
Fri Jun 08 2012 13:53:03 GMT+0100 (IST)
training:PRIMARY> new Date()
ISODate("2012-06-08T12:53:06.831Z")

training:PRIMARY> var start = new Date("21/May/2012:16:35:33 -0400")        => doesn't work
training:PRIMARY> start
ISODate("0NaN-NaN-NaNTNaN:NaN:NaNZ")

training:PRIMARY> var start = new Date("21 May 2012:16:35:33 -0400")        => doesn't work    
training:PRIMARY> start
ISODate("0NaN-NaN-NaNTNaN:NaN:NaNZ")

training:PRIMARY> var start = new Date("21 May 2012 16:35:33 -0400")        => works
training:PRIMARY> start
ISODate("2012-05-21T20:35:33Z")

Voici quelques liens qui pourraient vous être utiles (concernant la modification des données dans le shell mongo) - 

http://cookbook.mongodb.org/patterns/date_range/

http://www.mongodb.org/display/DOCS/Dates

http://www.mongodb.org/display/DOCS/Overview+-+The+MongoDB+Interactive+Shell

7
Mark Hillick

Dans mon cas, la solution suivante a été utilisée pour convertir le champ ClockInTime de la collection ClockTime de la chaîne au type de date :

db.ClockTime.find().forEach(function(doc) { 
    doc.ClockInTime=new Date(doc.ClockInTime);
    db.ClockTime.save(doc); 
    })
34
Ciges

Utilisation de MongoDB 4.0 et plus récent

L'opérateur $toDate convertira la valeur en date. Si la valeur ne peut pas être convertie en date, les erreurs $toDate. Si la valeur est null ou manquante, $toDate renvoie null:

Vous pouvez l'utiliser dans un pipeline d'agrégats comme suit:

db.collection.aggregate([
    { "$addFields": {
        "created_at": {
            "$toDate": "$created_at"
        }
    } }
])

Ce qui précède revient à utiliser l'opérateur $convert comme suit:

db.collection.aggregate([
    { "$addFields": {
        "created_at": { 
            "$convert": { 
                "input": "$created_at", 
                "to": "date" 
            } 
        }
    } }
])

Utilisation de MongoDB 3.6 et plus récent

Vous pouvez également utiliser l'opérateur $dateFromString qui convertit la chaîne de date/heure en objet de date et propose des options permettant de spécifier le format de date et le fuseau horaire:

db.collection.aggregate([
    { "$addFields": {
        "created_at": { 
            "$dateFromString": { 
                "dateString": "$created_at",
                "format": "%m-%d-%Y" /* <-- option available only in version 4.0. and newer */
            } 
        }
    } }
])

Utilisation des versions de MongoDB >= 2.6 and < 3.2

Si la version de MongoDB ne contient pas les opérateurs natifs qui effectuent la conversion, vous devez itérer manuellement le curseur renvoyé par la méthode find() à l'aide de la méthode forEach() méthode ou la méthode du curseur next() pour accéder aux documents. A l'aide de la boucle, convertissez le champ en objet ISODate, puis mettez-le à jour à l'aide de l'opérateur $set, comme dans l'exemple suivant où le champ est appelé created_at et contient actuellement la date au format chaîne. :

var cursor = db.collection.find({"created_at": {"$exists": true, "$type": 2 }}); 
while (cursor.hasNext()) { 
    var doc = cursor.next(); 
    db.collection.update(
        {"_id" : doc._id}, 
        {"$set" : {"created_at" : new ISODate(doc.created_at)}}
    ) 
};

Pour améliorer les performances, en particulier dans le cas de collections volumineuses, tirez parti de l’utilisation de API EN BLOC pour les mises à jour en masse, car vous enverrez les opérations au serveur par lots de 1000, ce qui vous donne une meilleure performances, car vous n’envoyez pas chaque requête au serveur, une seule demande sur 1000. 

Ce qui suit illustre cette approche. Le premier exemple utilise l'API en bloc disponible dans les versions de MongoDB >= 2.6 and < 3.2. Il met à jour tous les documents de la collection en modifiant les champs created_at en champs de date:

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

db.collection.find({"created_at": {"$exists": true, "$type": 2 }}).forEach(function (doc) {
    var newDate = new ISODate(doc.created_at);
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "created_at": newDate}
    });

    counter++;
    if (counter % 1000 == 0) {
        bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})
// Clean up remaining operations in queue
if (counter % 1000 != 0) { bulk.execute(); }

Utilisation de MongoDB 3.2

L'exemple suivant s'applique à la nouvelle version de MongoDB 3.2 qui a depuis OBSOL&EGRAVE;TE L'API EN BLOC et a fourni un jeu plus récent d'apis utilisant bulkWrite():

var bulkOps = [],
    cursor = db.collection.find({"created_at": {"$exists": true, "$type": 2 }});

cursor.forEach(function (doc) { 
    var newDate = new ISODate(doc.created_at);
    bulkOps.Push(         
        { 
            "updateOne": { 
                "filter": { "_id": doc._id } ,              
                "update": { "$set": { "created_at": newDate } } 
            }         
        }           
    );

    if (bulkOps.length === 500) {
        db.collection.bulkWrite(bulkOps);
        bulkOps = [];
    }     
});

if (bulkOps.length > 0) db.collection.bulkWrite(bulkOps);
13
chridam

J'avais des chaînes dans MongoDB Stored qui devaient être reformatées en un champ dateTime correct et valide dans mongodb.

voici mon code pour le format de date spécial: "2014-03-12T09: 14: 19.5303017 + 01: 00"

mais vous pouvez facilement prendre cette idée et écrire votre propre regex pour analyser les formats de date:

// format: "2014-03-12T09:14:19.5303017+01:00"
var myregexp = /(....)-(..)-(..)T(..):(..):(..)\.(.+)([\+-])(..)/;

db.Product.find().forEach(function(doc) { 
   var matches = myregexp.exec(doc.metadata.insertTime);

   if myregexp.test(doc.metadata.insertTime)) {
       var offset = matches[9] * (matches[8] == "+" ? 1 : -1);
       var hours = matches[4]-(-offset)+1
       var date = new Date(matches[1], matches[2]-1, matches[3],hours, matches[5], matches[6], matches[7] / 10000.0)
       db.Product.update({_id : doc._id}, {$set : {"metadata.insertTime" : date}})
       print("succsessfully updated");
    } else {
        print("not updated");
    }
})
3
Pascalsz

Vous pouvez utiliser $dateFromString agrégation qui convertit la date de chaîne en date ISO

db.collection.aggregate([
  {
    "$project": {
      "date": {
        "$dateFromString": {
          "dateString": "$date"
        }
      }
    }
  }
])
0
Anthony Winzlet

Pourquoi ne pas utiliser une bibliothèque comme momentjs en écrivant un script du genre

[install_moment.js]
function get_moment(){
    // shim to get UMD module to load as CommonJS
    var module = {exports:{}};

    /* 
    copy your favorite UMD module (i.e. moment.js) here
    */

    return module.exports
}
//load the module generator into the stored procedures: 
db.system.js.save( {
        _id:"get_moment",
        value: get_moment,
    });

Ensuite, chargez le script sur la ligne de commande comme suit: 

> mongo install_moment.js

Enfin, dans votre prochaine session de mongo, utilisez-le comme suit: 

// LOAD STORED PROCEDURES
db.loadServerScripts();

// GET THE MOMENT MODULE
var moment = get_moment();

// parse a date-time string
var a = moment("23 Feb 1997 at 3:23 pm","DD MMM YYYY [at] hh:mm a");

// reformat the string as you wish:
a.format("[The] DDD['th day of] YYYY"): //"The 54'th day of 1997"
0
Jthorpe