복붙노트

[MONGODB] C 번호로 집계 $ 조회

MONGODB

C 번호로 집계 $ 조회

나는 다음과 같은 MongoDB의 쿼리 작업이 :

db.Entity.aggregate(
    [
        {
            "$match":{"Id": "12345"}
        },
        {
            "$lookup": {
                "from": "OtherCollection",
                "localField": "otherCollectionId",
                "foreignField": "Id",
                "as": "ent"
            }
        },
        { 
            "$project": { 
                "Name": 1,
                "Date": 1,
                "OtherObject": { "$arrayElemAt": [ "$ent", 0 ] } 
            }
        },
        { 
            "$sort": { 
                "OtherObject.Profile.Name": 1
            } 
        }
    ]
)

이것은 다른 집합으로부터 매칭 오브젝트와 결합 객체의리스트를 검색한다.

사람의 알고는 나도 LINQ를 사용하거나이 정확한 문자열을 사용하여 C #에서 이것을 사용할 수 있는가하는 방법?

나는 그들이 더 이상 사용되지 않습니다 것 같아요 - 나는 다음과 같은 코드를 사용하여 시도하지만 QueryDocument 및 MongoCursor의 유형을 찾을 수 없습니다?

BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{ name : value }");
QueryDocument queryDoc = new QueryDocument(document);
MongoCursor toReturn = _connectionCollection.Find(queryDoc);

해결법

  1. ==============================

    1.JSON을 구문 분석 할 필요가 없습니다. 여기에 모든 것이 실제로 LINQ 또는 집계 유창함 인터페이스 중 하나를 직접 수행 할 수 있습니다.

    JSON을 구문 분석 할 필요가 없습니다. 여기에 모든 것이 실제로 LINQ 또는 집계 유창함 인터페이스 중 하나를 직접 수행 할 수 있습니다.

    문제는 정말 갈 훨씬 제공하지 않기 때문에 그냥 몇 가지 데모 클래스를 사용하여.

    기본적으로 우리가되고, 여기에 두 개의 컬렉션이

    엔티티

    { "_id" : ObjectId("5b08ceb40a8a7614c70a5710"), "name" : "A" }
    { "_id" : ObjectId("5b08ceb40a8a7614c70a5711"), "name" : "B" }
    

    다른 사람

    {
            "_id" : ObjectId("5b08cef10a8a7614c70a5712"),
            "entity" : ObjectId("5b08ceb40a8a7614c70a5710"),
            "name" : "Sub-A"
    }
    {
            "_id" : ObjectId("5b08cefd0a8a7614c70a5713"),
            "entity" : ObjectId("5b08ceb40a8a7614c70a5711"),
            "name" : "Sub-B"
    }
    

    그리고 클래스의 몇 그들을 그냥 아주 기본적인 예제에 바인딩 :

    public class Entity
    {
      public ObjectId id;
      public string name { get; set; }
    }
    
    public class Other
    {
      public ObjectId id;
      public ObjectId entity { get; set; }
      public string name { get; set; }
    }
    
    public class EntityWithOthers
    {
      public ObjectId id;
      public string name { get; set; }
      public IEnumerable<Other> others;
    }
    
     public class EntityWithOther
    {
      public ObjectId id;
      public string name { get; set; }
      public Other others;
    }
    
    var listNames = new[] { "A", "B" };
    
    var query = entities.Aggregate()
        .Match(p => listNames.Contains(p.name))
        .Lookup(
          foreignCollection: others,
          localField: e => e.id,
          foreignField: f => f.entity,
          @as: (EntityWithOthers eo) => eo.others
        )
        .Project(p => new { p.id, p.name, other = p.others.First() } )
        .Sort(new BsonDocument("other.name",-1))
        .ToList();
    

    요청이 서버로 전송 :

    [
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : { 
        "from" : "others",
        "localField" : "_id",
        "foreignField" : "entity",
        "as" : "others"
      } }, 
      { "$project" : { 
        "id" : "$_id",
        "name" : "$name",
        "other" : { "$arrayElemAt" : [ "$others", 0 ] },
        "_id" : 0
      } },
      { "$sort" : { "other.name" : -1 } }
    ]
    

    유창 인터페이스는 기본적으로 일반 BSON 구조와 동일하기 때문에 아마도 가장 쉬운 이해합니다. $ 조회 단계 모두를 동일한 인수를 보유하고 $ arrayElemAt을 처음에 표시된다 (). $의 경우 종류 당신은 단순히 BSON 문서 또는 다른 유효한 식을 제공 할 수 있습니다.

    또 다른 위 MongoDB를 3.6과의 하위 파이프 라인 문 $ 조회의 새로운 표현 형태이다.

    BsonArray subpipeline = new BsonArray();
    
    subpipeline.Add(
      new BsonDocument("$match",new BsonDocument(
        "$expr", new BsonDocument(
          "$eq", new BsonArray { "$$entity", "$entity" }  
        )
      ))
    );
    
    var lookup = new BsonDocument("$lookup",
      new BsonDocument("from", "others")
        .Add("let", new BsonDocument("entity", "$_id"))
        .Add("pipeline", subpipeline)
        .Add("as","others")
    );
    
    var query = entities.Aggregate()
      .Match(p => listNames.Contains(p.name))
      .AppendStage<EntityWithOthers>(lookup)
      .Unwind<EntityWithOthers, EntityWithOther>(p => p.others)
      .SortByDescending(p => p.others.name)
      .ToList();
    

    요청이 서버로 전송 :

    [ 
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : {
        "from" : "others",
        "let" : { "entity" : "$_id" },
        "pipeline" : [
          { "$match" : { "$expr" : { "$eq" : [ "$$entity", "$entity" ] } } }
        ],
        "as" : "others"
      } },
      { "$unwind" : "$others" },
      { "$sort" : { "others.name" : -1 } }
    ]
    

    유창 "빌더"직접 아직 구문을 지원하거나하지 않습니다 LINQ 표현하지만 여전히 BsonDocument 및 BsonArray 또는 다른 유효한 표현식을 사용하여 구성 할 수있다,는 $ EXPR 연산자를 지원합니다. 여기에서 우리는 또한 일종의 표현보다는 이전 같이 BsonDocument를 사용하여 $을 적용하기 위해 $ 언 와인드 결과를 "입력".

    이외에도 다른 용도로부터 "하위 파이프 라인 '의 주요 임무는 $ 조회의 대상 배열에 반환 된 문서를 줄이는 것입니다. 이것은 일반적으로 단지 결과 배열의 첫 번째 요소를 잡는 것보다 더 효율적 그래서 또한 언 와인드 여기에 $ 실제로 서버 실행에 $ 조회 문에 "통합"되는 목적을 제공합니다.

    var query = entities.AsQueryable()
        .Where(p => listNames.Contains(p.name))
        .GroupJoin(
          others.AsQueryable(),
          p => p.id,
          o => o.entity,
          (p, o) => new { p.id, p.name, other = o.First() }
        )
        .OrderByDescending(p => p.other.name);
    

    요청이 서버로 전송 :

    [ 
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : {
        "from" : "others",
        "localField" : "_id",
        "foreignField" : "entity",
        "as" : "o"
      } },
      { "$project" : {
        "id" : "$_id",
        "name" : "$name",
        "other" : { "$arrayElemAt" : [ "$o", 0 ] },
        "_id" : 0
      } },
      { "$sort" : { "other.name" : -1 } }
    ]
    

    이것은 거의 동일하지만, 단지 다른 인터페이스를 사용하고 약간 다른 BSON 문을 생성하고, 정말 때문 만이 기능 문에서 단순화 된 이름의. 이것은 단순히) (A SelectMany에서 생산 된 같은 $의 풀림을 사용하는 다른 가능성을 가지고 않습니다 :

    var query = entities.AsQueryable()
      .Where(p => listNames.Contains(p.name))
      .GroupJoin(
        others.AsQueryable(),
        p => p.id,
        o => o.entity,
        (p, o) => new { p.id, p.name, other = o }
      )
      .SelectMany(p => p.other, (p, other) => new { p.id, p.name, other })
      .OrderByDescending(p => p.other.name);
    

    요청이 서버로 전송 :

    [
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : {
        "from" : "others",
        "localField" : "_id",
        "foreignField" : "entity",
        "as" : "o"
      }},
      { "$project" : {
        "id" : "$_id",
        "name" : "$name",
        "other" : "$o",
        "_id" : 0
      } },
      { "$unwind" : "$other" },
      { "$project" : {
        "id" : "$id",
        "name" : "$name",
        "other" : "$other",
        "_id" : 0
      }},
      { "$sort" : { "other.name" : -1 } }
    ]
    

    일반적으로 직접 $ 조회 다음 언 와인드 $를 배치하는 것은 실제로 통합 프레임 워크에 대한 "최적의 패턴"입니다. 그러나 .NET 드라이버는 혼란을 사이에 $ 프로젝트를 강요하기보다는 "등"에 대한 묵시적 이름을 사용하여이 조합이 최대 않습니다. 하지 그에 대한 경우 당신은 당신이 "하나"관련 결과를 알고있을 때,이 사실은 더 $의 arrayElemAt보다. 당신이 "합체"언 와인드 $을 원하는 경우에, 당신은 더 유창 인터페이스, 이상을 보여 같은 다른 양식을 사용하여 꺼져 있습니다.

    var query = from p in entities.AsQueryable()
                where listNames.Contains(p.name) 
                join o in others.AsQueryable() on p.id equals o.entity into joined
                select new { p.id, p.name, other = joined.First() }
                into p
                orderby p.other.name descending
                select p;
    

    요청이 서버로 전송 :

    [
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : {
        "from" : "others",
        "localField" : "_id",
        "foreignField" : "entity",
        "as" : "joined"
      } },
      { "$project" : {
        "id" : "$_id",
        "name" : "$name",
        "other" : { "$arrayElemAt" : [ "$joined", 0 ] },
        "_id" : 0
      } },
      { "$sort" : { "other.name" : -1 } }
    ]
    

    모든 꽤 친숙하고 정말 그냥 아래로 기능 명명합니다. 그냥 $ 언 와인드 옵션을 사용하여와 같은 :

    var query = from p in entities.AsQueryable()
                where listNames.Contains(p.name) 
                join o in others.AsQueryable() on p.id equals o.entity into joined
                from sub_o in joined.DefaultIfEmpty()
                select new { p.id, p.name, other = sub_o }
                into p
                orderby p.other.name descending
                select p;
    

    요청이 서버로 전송 :

    [ 
      { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
      { "$lookup" : {
        "from" : "others",
        "localField" : "_id",
        "foreignField" : "entity",
        "as" : "joined"
      } },
      { "$unwind" : { 
        "path" : "$joined", "preserveNullAndEmptyArrays" : true
      } }, 
      { "$project" : { 
        "id" : "$_id",
        "name" : "$name",
        "other" : "$joined",
        "_id" : 0
      } }, 
      { "$sort" : { "other.name" : -1 } }
    ]
    

    실제로 "최적화 합체"양식을 사용하고있다. 번역자는 여전히 우리가 문을 유효하게하기 위해 중간 선택을 필요로하기 때문에 $ 프로젝트를 추가하는 주장한다.

    그래서 본질적으로 정확히 같은 결과를 같은 쿼리 문 기본적으로 무엇인지에 도착하기 위해 꽤 몇 가지 방법이 있습니다. 당신이 BsonDocument 양식으로 JSON을 구문 분석하고 유창 집계 () 명령이 먹이를 "수"동안, 그들이 쉽게 같은 문에지도 않는 자연 빌더 또는 LINQ 인터페이스를 사용하는 것이 일반적으로 좋습니다.

    $ 해제하는 옵션은 크게 표시되기 때문에 심지어 "합체"형태는 실제로 훨씬 더 최적의 후 "첫 번째"배열 요소를 취할 $ arrayElemAt을 사용하고있는 "단수"일치와. $ 조회 대상 배열이 부모 문서가 더 필터링없이 16메가바이트을 초과 할 수있는 곳도 BSON 제한 같은 것들의 고려 사항 더 중요합니다. 일치하는 파이프 라인에서 문서의 집계 $ 조회 총 크기에 여기에 또 다른 게시물이 실제로에만이 시간에 능통 인터페이스에 사용할 수 등의 옵션 또는 기타 조회 () 구문을 사용하여 박히는 그 한계를 방지하는 방법에 대해 설명 최대 문서 크기를 초과 .

  2. ==============================

    2.여기 MongoDB.Entities 함께 할 방법은 다음과 같습니다. 두 기관 중 하나 일대 다 또는 다 대다 관계에있는 경우에, 당신은 다음과 같이 수동으로 조인 할 필요없이 역의 관계에 액세스 할 수 있습니다. [면책 조항 : 나는 라이브러리의 저자 해요]

    여기 MongoDB.Entities 함께 할 방법은 다음과 같습니다. 두 기관 중 하나 일대 다 또는 다 대다 관계에있는 경우에, 당신은 다음과 같이 수동으로 조인 할 필요없이 역의 관계에 액세스 할 수 있습니다. [면책 조항 : 나는 라이브러리의 저자 해요]

    using System;
    using System.Linq;
    using MongoDB.Entities;
    using MongoDB.Driver.Linq;
    
    namespace StackOverflow
    {
        public class Program
        {
            public class Author : Entity
            {
                public string Name { get; set; }
                public Many<Book> Books { get; set; }
    
                public Author() => this.InitOneToMany(() => Books);
            }
    
            public class Book : Entity
            {
                public string Title { get; set; }
            }
    
            static void Main(string[] args)
            {
                new DB("test");
    
                var book = new Book { Title = "The Power Of Now" };
                book.Save();
    
                var author = new Author { Name = "Eckhart Tolle" };
                author.Save();
    
                author.Books.Add(book);
    
                //build a query for finding all books that has Power in the title.
                var bookQuery = DB.Queryable<Book>()
                                  .Where(b => b.Title.Contains("Power"));
    
                //find all the authors of books that has a title with Power in them
                var authors = author.Books
                                    .ParentsQueryable<Author>(bookQuery); //also can pass in an ID or array of IDs
    
                //get the result
                var result = authors.ToArray();
    
                //output the aggregation pipeline
                Console.WriteLine(authors.ToString());
    
    
                Console.ReadKey();
            }
        }
    }
    
  3. from https://stackoverflow.com/questions/50530363/aggregate-lookup-with-c-sharp by cc-by-sa and MIT license