MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Remodeler les documents en divisant une valeur de champ

La manière optimale dans MongoDB version 3.4.

Cette version de mongod fournit le $split opérateur qui, bien sûr, divise la chaîne comme indiqué ici .

Nous attribuons ensuite la valeur nouvellement calculée à une variable à l'aide du $let opérateur variable. La nouvelle valeur peut ensuite être utilisée dans le in expression pour renvoyer les valeurs "name" et "age" en utilisant le $arrayElemAt opérateur pour renvoyer l'élément à un index spécifié ; 0 pour le premier élément et -1 pour le dernier élément.

Notez que dans le dans expression, nous devons diviser le dernier élément afin de renvoyer la chaîne d'entier.

Enfin, nous devons itérer le Cursor objet et convertir la chaîne d'entier en numérique en utilisant Number ou parseInt et utilisez l'opération en bloc et le bulkWrite() méthode pour $set la valeur de ces champs pour une efficacité maximale.

let requests = [];
db.coll.aggregate(
    [
        { "$project": {  
            "person": { 
                "$let": { 
                    "vars": { 
                        "infos":  { "$split": [ "$person", "," ] } 
                    }, 
                    "in": { 
                        "name": { "$arrayElemAt": [ "$$infos", 0 ] }, 
                        "age": { 
                            "$arrayElemAt": [ 
                                { "$split": [ 
                                    { "$arrayElemAt": [ "$$infos", -1 ] }, 
                                    " " 
                                ]}, 
                                -1 
                            ] 
                        } 
                    } 
                } 
            }  
        }}
    ] 
).forEach(document => { 
    requests.push({ 
        "updateOne": { 
            "filter": { "_id": document._id }, 
            "update": { 
                "$set": { 
                    "name": document.person.name, 
                    "age": Number(document.person.age) 
                },
                "$unset": { "person": " " }
            } 
        } 
    }); 
    if ( requests.length === 500 ) { 
        // Execute per 500 ops and re-init
        db.coll.bulkWrite(requests); 
        requests = []; 
    }} 
);

 // Clean up queues
if(requests.length > 0) {
    db.coll.bulkWrite(requests);
}

MongoDB 3.2 ou plus récent.

MongoDB 3.2 déprécie l'ancien Bulk() API et ses méthodes et fournit le bulkWrite() mais elle ne fournit pas le $split donc la seule option que nous avons ici est d'utiliser le mapReduce() méthode pour transformer nos données puis mettre à jour la collection en utilisant une opération en masse.

var mapFunction = function() { 
    var person = {}, 
    infos = this.person.split(/[,\s]+/); 
    person["name"] = infos[0]; 
    person["age"] = infos[2]; 
    emit(this._id, person); 
};

var results = db.coll.mapReduce(
    mapFunction, 
    function(key, val) {}, 
    { "out": { "inline": 1 } }
)["results"];

results.forEach(document => { 
    requests.push({ 
        "updateOne": { 
            "filter": { "_id": document._id }, 
            "update": { 
                "$set": { 
                    "name": document.value.name, 
                    "age": Number(document.value.age) 
                }, 
                "$unset": { "person": " " }
            } 
        } 
    }); 
    if ( requests.length === 500 ) { 
        // Execute per 500 operations and re-init
        db.coll.bulkWrite(requests); 
        requests = []; 
    }} 
);

// Clean up queues
if(requests.length > 0) {
    db.coll.bulkWrite(requests);
}

MongoDB version 2.6 ou 3.0.

Nous devons utiliser l'API Bulk désormais obsolète .

var bulkOp = db.coll.initializeUnorderedBulkOp();
var count = 0;

results.forEach(function(document) { 
    bulkOp.find({ "_id": document._id}).updateOne(
        { 
            "$set": { 
                "name": document.value.name, 
                "age": Number(document.value.age)
            },
            "$unset": { "person": " " }
        }
    );
    count++;
    if (count === 500 ) {
        // Execute per 500 operations and re-init
        bulkOp.execute();
        bulkOp = db.coll.initializeUnorderedBulkOp();
    }
});

// clean up queues
if (count > 0 ) {
    bulkOp.execute();
}