web-dev-qa-db-fra.com

Élément de tableau de mise à jour Mongo (pilote .NET 2.0)

EDIT: Ne cherche pas la manière javascript de faire cela. Je suis à la recherche de la méthode du pilote MongoDB C # 2.0 (je sais que cela n’est peut-être pas possible; mais j’espère que quelqu'un connaît une solution).

J'essaie de mettre à jour la valeur d'un élément incorporé dans un tableau du document principal dans mon mongodb.

Je cherche un moyen fortement typé de le faire. J'utilise le pilote Mongodb c # 2.0

Je peux le faire en sautant l'élément, en mettant à jour la valeur, puis en le réinsérant. Cela ne me semble pas juste. puisque je remplace ce qui aurait pu être écrit entre-temps.

Voici ce que j'ai essayé jusqu'à présent, mais sans succès:

private readonly IMongoCollection<TempAgenda> _collection;

void Main()
{
    var collectionName = "Agenda";
    var client = new MongoClient("mongodb://localhost:27017");
    var db = client.GetDatabase("Test");
    _collection = db.GetCollection<TempAgenda>(collectionName);
    UpdateItemTitle(1, 1, "hello");
}

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Eq(x => x.AgendaId, agendaId);
    var update = Builders<TempAgenda>.Update.Set(x => x.Items.Single(p => p.Id.Equals(itemId)).Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}
14
Kristian Barrett

Il m'a fallu un certain temps pour comprendre cela, car cela ne semble pas être mentionné dans aucun des documents officiels (ou ailleurs). J'ai cependant trouvé this sur leur traqueur de problème, ce qui explique comment utiliser l'opérateur positionnel $ avec le pilote C # 2.0.

Cela devrait faire ce que vous voulez:

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items[-1].Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

Notez que votre clause Item.Single() a été remplacée par Item.Any() et déplacée vers la définition de filtre.

[-1] ou .ElementAt(-1) est apparemment traité spécialement (en fait tout <0) et sera remplacé par l'opérateur positionnel $.

Ce qui précède sera traduit à cette requête:

db.Agenda.update({ AgendaId: 1, Items.Id: 1 }, { $set: { Items.$.Title: "hello" } })
43
Søren Kruse

Merci, c'était utile. J'ai un ajout cependant, j'ai utilisé ce qui précède pour les tableaux, poussant vers un tableau imbriqué et en tirant à partir d'un. Le problème que j'ai constaté est que si j'avais un tableau int (donc pas un objet, mais simplement un tableau int), le PullFilter ne fonctionnait pas réellement - "Impossible de déterminer les informations de sérialisation", ce qui est étrange, car il ne s'agit que d'un tableau des ints. J'ai fini par créer un tableau d'objets avec un seul paramètre int, et tout a commencé à fonctionner. Peut-être un bug, ou peut-être mon manque de compréhension. Quoi qu'il en soit, comme j'ai eu du mal à trouver des informations sur l'extraction et le transfert de tableaux d'objets imbriqués avec le pilote C # 2.0, j'ai pensé que je devrais publier mes résultats ici, car ils utilisent la syntaxe ci-dessus.

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.PullFilter(x => x.NestedArray.ElementAt(-1).User, Builders<User>.Filter.Eq(f => f.UserID, userID));
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);

Et aussi:

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.Push(x => x.NestedArray.ElementAt(-1).Users, new User { UserID = userID });
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);
1
davoc bradley