2017-12-26 15 views
0

MongoDBのドキュメントの子配列の子要素を変更するにはどうすればよいですか?私はMongoDB(C#ドライババージョン:2.5、サーババージョン:3.2.0)の最新のC#ドライバを使用していますが、私はSO(重複した質問もあります)ソース。ほとんどのソリューションは時代遅れであることが判明しました。以下はC#ドライバを使用してMongoDB Arrayの子ドキュメントを更新する方法

私のサンプル文書です:

[{ 
"_id" : "69c4f77d-05ef-431d-ae17-c076c6173e04",  
"title" : "Root Page", 
"createdAt" : ISODate("2017-12-21T12:28:00.680+0000"), 
"modifiedAt" : ISODate("2017-12-26T07:18:11.165+0000"), 
"pages" : [ 
    { 
     "_id" : "f449dc0b-3d1b-4a59-b622-6a42ce10b147", 
     "title" : "Test page 1", 
     "slug" : "test-page-1", 
     "createdAt" : ISODate("2017-12-21T12:28:00.680+0000"), 
     "modifiedAt" : ISODate("2017-12-21T12:28:00.680+0000") 
    }, 
    { 
     "_id" : "3d1497d7-f74c-4d88-b15c-bf2f9c736374", 
     "title" : "Test page 2", 
     "slug" : "test-page-2", 
     "createdAt" : ISODate("2017-12-25T11:27:55.006+0000"), 
     "modifiedAt" : ISODate("2017-12-25T11:27:55.006+0000") 
    }, 
    { 
     "_id" : "6e827e2a-5a25-4343-b646-885816bb8cc4", 
     "title" : "Test page 3", 
     "slug" : "test-page-3", 
     "createdAt" : ISODate("2017-12-25T11:31:16.516+0000"), 
     "modifiedAt" : ISODate("2017-12-25T11:31:16.516+0000") 
    }] 
}, 
..., 
... 
] 

文書構造: ルートドキュメントは、それがメタデータやページ(配列)のリストのしているサブ文書の配列を含み、

サブインサイドドキュメント - 私はページ配列内の子ページオブジェクトのタイトルスラグを更新しようとしたが、持っています最新のドライバーでこれまでのところ運がない。

私は次のフィルタと更新クエリを使用しています:

 var filter = Builders<SubDocument>.Filter.And(Builders<SubDocument>.Filter.Eq("_id", "xxx"), Builders<SubDocument>.Filter.ElemMatch(x => x.Pages, p => p.Id == "xxx")); 

     var update = Builders<SubDocument>.Update 
         .Set("pages.$.title", "changed title") 
         .Set("pages.$.slug", "changed-title") 
         .Set("pages.$.modifiedAt", DateTime.UtcNow); 

     _mongoDb.Documents.UpdateOne(filter, update); 

- このクエリは私にエラーを返します:

Invalid BSON field name pages.$.title

私は最後の数時間のために一緒に来た参照がに言っています"$"演算子を使用しますが、最新のドライバでエラーが発生します。

[編集1]は、ここに私のモデルです:

public class SubDocument 
{ 
    public SubDocument() 
    { 
     Id = Guid.NewGuid().ToString(); 
     CreatedAt = DateTime.UtcNow; 
     ModifiedAt = DateTime.UtcNow; 
     Pages = new List<Page>(); 
    } 

    [BsonId] 
    public string Id { get; set; }   

    [BsonElement("title")] 
    public string Title { get; set; }   

    [BsonElement("createdAt")] 
    public DateTime CreatedAt { get; set; } 

    [BsonElement("modifiedAt")] 
    public DateTime ModifiedAt { get; set; } 

    [BsonElement("pages")] 
    public List<Page> Pages { get; set; } 


} 

public class Page 
{ 
    [BsonId] 
    public string Id { get; set; } 

    [BsonElement("title")] 
    public string Title { get; set; } 

    [BsonElement("slug")] 
    public string Slug { get; set; } 

    [BsonElement("createdAt")] 
    public DateTime CreatedAt { get; set; } 

    [BsonElement("modifiedAt")] 
    public DateTime ModifiedAt { get; set; } 

} 

誰ですか?前もって感謝します!

+0

どの要素を更新する必要がありますか?またはすべてのページ?フィルターはありますか? – Evk

+0

こんにちは@Evk、私は、PS、感謝の質問を更新しました! –

+0

SubDocumentのモデルも含めることができますか?ちょうどその人がそれを貼り付けることができるように – Evk

答えて

0

あなたのコードは実際にmongod v3.4とドライバv2.5で動作します。

コメント内でEvkが提案したように、リファクタリングが容易な厳密に型指定されたコードがここにあります。別のアプローチは、このように常に完全にエンティティを更新し、R-のDBMSの場合は可能性が高いきめ細かい更新を(回避、(ドキュメント指向のデータベースは、このアプローチを奨励)、全体としてサブ文書の実体を考慮するかもしれない

var filter = Builders<SubDocument>.Filter 
    .And(
     Builders<SubDocument>.Filter.Eq(d => d.Id, "69c4f77d-05ef-431d-ae17-c076c6173e04"), 
     Builders<SubDocument>.Filter.ElemMatch(x => x.Pages, p => p.Id == "3d1497d7-f74c-4d88-b15c-bf2f9c736374")); 

var update = Builders<SubDocument>.Update 
       .Set(c => c.Pages[-1].Title, "changed title") 
       .Set(c => c.Pages[-1].Slug, "changed slug") 
       .Set(c => c.Pages[-1].ModifiedAt, DateTime.UtcNow); 

subDocumentsCollection.UpdateOne(filter, update); 

)。この場合、あなたはこのようなことを書くかもしれません。

var document = subDocumentsCollection 
    .Find(d => d.Id == "69c4f77d-05ef-431d-ae17-c076c6173e04") 
    .Single(); 

var page = document.Pages.Single(p => p.Id == "3d1497d7-f74c-4d88-b15c-bf2f9c736374"); 

page.Title = "changed title"; 
page.Slug = "changed slug"; 
page.ModifiedAt = DateTime.UtcNow; 

subDocumentsCollection.ReplaceOne(d => d.Id == document.Id, document); 

この第2のアプローチは、以下のPROおよびCONを有する。

PROの

  • 更新は、このようにすべてのドメインのルールの適用を可能にし、データベースに入るダーティデータを防止する、(おそらく非常に適した方法を介して)ドメイン層に起こります。オブジェクト指向のよりです。
  • コードはドメイン指向なので、コードははるかに簡単でデータベースの内部構造に依存しません。

CONの

  • このアプローチは、データベース(読み出し用と更新用)上の2本のヒットを必要とします。
  • あなたのエンティティが大きい場合、ネットワークは厳密に必要以上のデータを転送する必要があります。最初の1だけでにフォールバック、私は第二のアプローチのために行くだろう、一般的に、

時期尚早の最適化は諸悪の根源であることを考慮すると(あるいは、少なくともそれのほとんど)プログラミングhere)で非常に厳しい性能要件または低いネットワーク帯域幅の場合。

関連する問題