2017-12-26 37 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

나는 지난 몇 시간 동안 함께 온 참조가 말을 "$"연산자를 사용하지만 최신 드라이버에 오류가 발생합니다.

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

} 

사람 :

[편집 1]은 여기 내 모델인가? 미리 감사드립니다!

+0

업데이트해야 할 요소와 값은 무엇입니까? 아니면 모든 페이지? 필터가 있으십니까? – Evk

+0

안녕하세요, @Evk, PS, 감사합니다. –

+0

SubDocument의 모델도 포함 할 수 있습니까? 그냥 하나 붙여 넣기 복사 할 수 있습니다 – Evk

답변

0

코드는 실제로 mongod v3.4 및 드라이버 v2.5에서 작동합니다.

의견 내에서 Evk이 제안한 것처럼 여기에는 리팩터링 방식의 코드가 포함 된 강력한 형식의 코드가 있습니다.

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

다른 접근 방법은 전체 (문서 지향 데이터베이스이 방법을 권장)와 같은 하위 개체를 고려해 볼 수 있습니다, 따라서 항상 전부 개체를 업데이트하고 세밀한 R-의 DBMS의 경우에 가능성이 업데이트 (피). 이 경우 다음과 같이 작성할 수 있습니다.

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

이 두 번째 방법은 다음과 같은 PRO 및 CON을가집니다. 따라서 모든 도메인 규칙의 적용을 가능하게하고, 데이터베이스로 이동하는 더티 데이터를 방지

프로

  • 업데이트가 (아마도 적합 방법을 통해) 영역 층에 일어난다; 따라서 더 많은 것 객체 지향적이다.
  • 코드는 도메인 지향적이기 때문에 훨씬 간단하고 데이터베이스 내부에 의존하지 않습니다.

단점

  • 이 방법은 데이터베이스 (읽기 다른 하나는 업데이트 한) 두 개의 안타를 요구한다
  • 엔티티가 큰 경우 네트워크는 엄격하게 필요한 것보다 많은 데이터를 전송해야합니다. 첫 번째 만에 다시 하락, 내가 두 번째 방법 갈 것입니다 일반적으로,

조기 최적화는 모든 악의 뿌리입니다 점을 감안하면 (또는 적어도 그것의 대부분) 프로그래밍 (here)에서 매우 엄격한 성능 요구 사항 또는 낮은 네트워크 대역폭의 경우.