2011-08-30 4 views
23

Dans la documentation officielle de MongoDB ils mentionnent upserts, donc ce serait vraiment bien d'écrire une commande upsert au lieu de:Upserting à Mongo DB en utilisant le pilote officiel C#

if (_campaignRepo.Exists(camp)) 
{ 
    _campaignRepo.DeleteByIdAndSystemId(camp); 
} 

_campaignRepo.Save(camp); 

quelque chose qui mettrait en œuvre cette logique sur la niveau db si c'est possible. Alors, quel est le moyen de faire un upsert s'il y en a un?

Répondre

25

Le code suivant est d'une application de travail:

weekplanStore.Update(
    Query.EQ("weekNumber", week), 
    Update.Replace(rawWeekPlan), 
    UpdateFlags.Upsert); 

Le weekplanStore est ma collection MongoDB, et le code mettra à jour le document trouvé avec la requête dans le premier argument ou insérez-en un nouveau si aucun n'est trouvé. Le "truc" est d'utiliser le modificateur UpdateFlags.Upsert.

Le rawWeekPlan est l'objet inséré ou mis à jour, et a le type suivant:

private class RawWeekPlan 
{ 
    public ObjectId id; 
    public int weekNumber; 
    public WeekPlanEntry[] entries; 
} 

et transformé en BSON par le pilote automatique.

+0

Est-ce que cela fonctionne pour les collections imbriquées? L'avez-vous essayé? Parce que ça ne marche pas pour eux dans mon cas –

+0

Je ne sais pas. Je ne l'ai pas essayé sur des collections imbriquées. –

+0

Le problème est dans id-s. J'ai demandé une question sur un autre thread –

39

La version 2 du pilote MongoDB C# requiert la définition de l'indicateur IsUpsert dans les commandes d'écriture. Cet exemple va augmenter un document entier.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } }; 
var result = await collection.ReplaceOneAsync(
    filter: new BsonDocument("_id", 123), 
    options: new UpdateOptions { IsUpsert = true } 
    replacement: newDoc); 

Version 1 du pilote MongoDB C# implémente cette logique au sein de la commande Save.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } }; 
collection.Save(newDoc); 

La méthode Save est une combinaison de mise à jour et d'insertion. Si le membre Id du document a une valeur, il est supposé être un document existant et Enregistrer les appels Mettre à jour sur le document (en définissant l'indicateur Upsert juste au cas où il s'agit réellement d'un nouveau document après tout). Sinon, il est supposé être un nouveau document et Enregistrer les appels Insert après avoir attribué une valeur unique nouvellement générée au membre Id.

Référence: http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method

Note: Ceci nécessite la mise en correspondance correcte du champ Id cependant. Plus d'informations sur ce ici: http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property

+0

Ce n'est plus possible avec la nouvelle API. –

+0

Mis à jour. Bien que je pense que la nouvelle API a rendu les commandes upsert plus difficiles à utiliser. –

+0

Que passe-t-on au filtre si l'ID newDocs est nul, c'est-à-dire s'il s'agit d'un insert? Juste un document bson vide? – BenCr

5

Vous pouvez utiliser la commande de mise à jour régulière, mais juste passer la mise à jour Upsert drapeau

MongoCollection collection = db.GetCollection("matches"); 
var query = new QueryDocument("recordId", recordId); 

var update = Update.Set("FirstName", "John").Set("LastName","Doe"); 
matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False); 

Ce code est adapté d'une application de travail (raccourci pour la clarté)

21

A partir de V2.0 le pilote il y a une nouvelle API async seulement. L'ancienne API ne doit plus être utilisée car elle est une façade bloquante sur la nouvelle API et est obsolète.

La façon recommandée actuellement à upsert un document est en appelant et en attente ReplaceOneAsync avec le drapeau IsUpsert allumé et un filtre correspondant au document pertinent:

Hamster hamster = ... 
var replaceOneResult = await collection.ReplaceOneAsync(
    doc => doc.Id == hamster.Id, 
    hamster, 
    new UpdateOptions {IsUpsert = true}); 

Vous pouvez vérifier si l'opération a été un insert ou une mise à jour en regardant ReplaceOneResult.MatchedCount:

+0

J'essaye d'employer ReplaceOneAsync mais il jette une exception: "le nom d'élément '' n'est pas valide", j'utilise le filtre pour updateOneasync cela fonctionne mais pas avec replaceone. Pouvez-vous m'aider s'il vous plaît? –

Questions connexes