web-dev-qa-db-ja.com

Mongo更新配列要素(.NETドライバー2.0)

編集:これを行うJavaScriptの方法を探していません。これを行うためのMongoDB C#2.0ドライバーの方法を探しています(それが不可能である可能性があることはわかっていますが、誰かが解決策を知っていることを願っています)。

私のmongodbのプライマリドキュメントの配列に埋め込まれたアイテムの値を更新しようとしています。

これを行うために強く型付けされた方法を探しています。私は Mongodb c#2.0ドライバー を使用しています

要素をポップし、値を更新してから、再挿入することでそれを行うことができます。これは正しくないと思います。その間に書かれたかもしれないものを上書きしているので。

これが私がこれまでに試したことですが、運がありません:

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;
}
20

公式ドキュメント(または他のどこでも)で言及されていないように見えるため、これを理解するにはしばらく時間がかかりました。ただし、C-2.0ドライバーで位置演算子_$_を使用する方法を説明する問題トラッカーで this を見つけました。

これはあなたが望むことをするはずです:

_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;
}
_

Item.Single()句がItem.Any()に変更され、フィルター定義に移動されていることに注意してください。

_[-1]_または.ElementAt(-1)は明らかに特別に扱われ(実際にはすべて<0)、位置演算子_$_に置き換えられます。

上記はこのクエリに翻訳されます:

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

ありがとう、これは役に立ちました。ただし、追加のものもあります。配列に対して上記を使用し、ネストされた配列にプッシュして、そこからプルしました。私が見つけた問題は、私がint配列(オブジェクトではなく、単純なint配列)を持っている場合、PullFilterが実際に機能しないことです-「シリアル化情報を判別できません」これは配列だけなので奇妙ですintの。私がやったことは、それをintパラメータが1つだけのオブジェクトの配列にして、すべてが機能し始めたことです。おそらくバグか、私の理解不足かもしれません。とにかく、C#2.0ドライバーで入れ子になったオブジェクト配列のプルとプッシュに関する情報を見つけるのに苦労してきたので、上記の構文を使用しているため、ここに私の発見を投稿する必要があると思いました。

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);

そしてまた:

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