MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Mongoose.aggregate (đường ống) liên kết nhiều bộ sưu tập bằng cách sử dụng $ unwind, $ lookup, $ group

Đây là một mẹo khó đối với người mới làm quen với MongoDb của aggregate . Tôi sẽ chia nhỏ câu trả lời của mình thành các bước để chứng minh cho những người khác đang cố gắng tổng hợp một mảng bằng cách tham chiếu nhiều tập hợp.

Bước 1 - $ đối sánh để lọc trên bộ sưu tập

Đối sánh $ chấp nhận các truy vấn giống như db.collection.find({}) và trả về một mảng kết quả phù hợp trong trường hợp bên dưới, tôi chọn 4 bản ghi cụ thể ở đây


{ '$match':
     { _id:
        { '$in':
           [
              ObjectId('5f7bdb3eea134b5a5c976285'),
              ObjectId('5f7bdb3eea134b5a5c976283'),
              ObjectId('5f7bdb3eea134b5a5c976284'),
              ObjectId('5f7bdb3eea134b5a5c976289')
           ]
        }
     }
}
$ match Kết quả
[ 
  { _id: ObjectId('5f7be0b37e2bdf5b19e4724d'),
    name: 'CAPTAIN_SAIL',
    classes: [ 'sail' ],
    license: 'WC-1',
    watercraftContexts:
     [ { _id: ObjectId('5f7be0b37e2bdf5b19e47241'),
         watercraftType: 'Sailboat',
         ref: 'sailboats' } ],
    __v: 0 },
  { _id: ObjectId('5f7be0b37e2bdf5b19e4724e'),
    name: 'CAPTAIN_YATCH',
    classes: [ 'yatch' ],
    license: 'WC-2',
    watercraftContexts:
     [ { _id: ObjectId('5f7be0b37e2bdf5b19e47242'),
         watercraftType: 'Yatch',
         ref: 'yatches' } ],
    __v: 0 },
  { _id: ObjectId('5f7be0b37e2bdf5b19e4724f'),
    name: 'CAPTAIN_SHIP',
    classes: [ 'ship' ],
    license: 'WC-3',
    watercraftContexts:
     [ { _id: ObjectId('5f7be0b37e2bdf5b19e47243'),
         watercraftType: 'Ship',
         ref: 'ships' } ],
    __v: 0 },
  { _id: ObjectId('5f7be0b37e2bdf5b19e47253'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     [ { _id: ObjectId('5f7be0b37e2bdf5b19e4724a'),
         watercraftType: 'Sailboat',
         ref: 'sailboats' },
       { _id: ObjectId('5f7be0b37e2bdf5b19e4724b'),
         watercraftType: 'Yatch',
         ref: 'yatches' },
       { _id: ObjectId('5f7be0b37e2bdf5b19e4724c'),
         watercraftType: 'Ship',
         ref: 'ships' } ],
    __v: 0 }
]

Bước 2 - $ unwind để chúng ta có thể lặp lại với $ loopup

Trong tập kết quả này có một mảng các đối tượng có { _id: <ObjectId>, watercraftType: <ModelName> } để lặp qua mảng và nối từng đối tượng này với bản ghi tập hợp tương ứng, chúng ta phải chia mảng thành các bản ghi độc lập riêng lẻ. $unwind tính năng sẽ tạo tập dữ liệu mới cho giai đoạn tổng hợp tiếp theo

  { '$unwind': '$watercraftContexts' },
$ unwind Kết quả

Như bạn có thể thấy $unwind bây giờ tạo một bản ghi với một watercraftContext duy nhất bây giờ chúng tôi được thiết lập để sử dụng $lookup

[ { _id: ObjectId('5f7be2231da37c5b5915bf9b'),
    name: 'CAPTAIN_SAIL',
    classes: [ 'sail' ],
    license: 'WC-1',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf8f'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0 },
  { _id: ObjectId('5f7be2231da37c5b5915bf9c'),
    name: 'CAPTAIN_YATCH',
    classes: [ 'yatch' ],
    license: 'WC-2',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf90'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0 },
  { _id: ObjectId('5f7be2231da37c5b5915bf9d'),
    name: 'CAPTAIN_SHIP',
    classes: [ 'ship' ],
    license: 'WC-3',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf91'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0 },
  { _id: ObjectId('5f7be2231da37c5b5915bfa1'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf98'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0 },
  { _id: ObjectId('5f7be2231da37c5b5915bfa1'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf99'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0 },
  { _id: ObjectId('5f7be2231da37c5b5915bfa1'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be2231da37c5b5915bf9a'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0 } ]
Bước 4 $ tra cứu - Kết hợp từng bản ghi từ bộ sưu tập nước ngoài

Điều quan trọng cần lưu ý là chúng ta phải $unwind trước khi gọi $lookup cho mỗi bộ sưu tập khác nhau, chúng tôi cần tham gia. Vì chúng tôi muốn kết hợp nhiều tập hợp, chúng tôi cần lưu trữ kết quả trong một đối tượng được khóa bởi tập hợp để tổng hợp sau này.

  // Only performs $lookup on 'ships' collection
  { '$lookup':
     { from: 'ships',  // Collection Name - Note: repeat for each collection
       localField: 'watercraftContexts._id', // The field with id to link
       foreignField: '_id',  // The field on the foreign collection to match
       as: 'watercrafts.ships' // The path where to store the lookup result
     }
  }

Bước 5 - Lặp lại tra cứu $ unwind và $ cho các phép nối khác

Lặp lại bước trên với các bước cho các phép nối bổ sung và khóa theo tên bộ sưu tập. Tôi đã kết hợp các giai đoạn tổng hợp để chứng minh sự lặp lại.

  { '$unwind': '$watercraftContexts' },
  { '$lookup':
     { from: 'yatches',
       localField: 'watercraftContexts._id',
       foreignField: '_id',
       as: 'watercrafts.yatches' } },
  { '$unwind': '$watercraftContexts' },
  { '$lookup':
     { from: 'sailboats',
       localField: 'watercraftContexts._id',
       foreignField: '_id',
       as: 'watercrafts.sailboats' } }
Bước 4 &5 Kết quả

Nếu quan sát kỹ, bạn nhận thấy rằng một trong những Captain bản ghi tồn tại 3 lần với một watercraftType khác . $lookup sẽ chỉ trả về các bản ghi khớp với tên bộ sưu tập cụ thể. Đây là lý do tại sao lại lưu trữ chúng trong một Object được khóa bởi collectionName

[
  { _id: ObjectId('5f7be7145320a65b942bb450'),
    name: 'CAPTAIN_SAIL',
    classes: [ 'sail' ],
    license: 'WC-1',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb444'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0,
    watercrafts:
     { ships: [],
       yatches: [],
       sailboats:
        [ { _id: ObjectId('5f7be7145320a65b942bb444'),
            class: 'sail',
            name: 'Gone with the Wind',
            __v: 0 } ] } },
  { _id: ObjectId('5f7be7145320a65b942bb451'),
    name: 'CAPTAIN_YATCH',
    classes: [ 'yatch' ],
    license: 'WC-2',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb445'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0,
    watercrafts:
     { ships: [],
       yatches:
        [ { _id: ObjectId('5f7be7145320a65b942bb445'),
            class: 'yatch',
            name: 'Liquid Gold',
            __v: 0 } ],
       sailboats: [] } },
  { _id: ObjectId('5f7be7145320a65b942bb452'),
    name: 'CAPTAIN_SHIP',
    classes: [ 'ship' ],
    license: 'WC-3',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb446'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    watercrafts:
     { ships:
        [ { _id: ObjectId('5f7be7145320a65b942bb446'),
            class: 'ship',
            name: 'Jenny',
            __v: 0 } ],
       yatches: [],
       sailboats: [] } },
  { _id: ObjectId('5f7be7145320a65b942bb456'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb44d'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0,
    watercrafts:
     { ships: [],
       yatches: [],
       sailboats:
        [ { _id: ObjectId('5f7be7145320a65b942bb44d'),
            class: 'sail',
            name: 'Swell Shredder',
            __v: 0 } ] } },
  { _id: ObjectId('5f7be7145320a65b942bb456'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb44e'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0,
    watercrafts:
     { ships: [],
       yatches:
        [ { _id: ObjectId('5f7be7145320a65b942bb44e'),
            class: 'yatch',
            name: 'Audrey',
            __v: 0 } ],
       sailboats: [] } },
  { _id: ObjectId('5f7be7145320a65b942bb456'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7be7145320a65b942bb44f'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    watercrafts:
     { ships:
        [ { _id: ObjectId('5f7be7145320a65b942bb44f'),
            class: 'ship',
            name: 'Jenny IV',
            __v: 0 } ],
       yatches: [],
       sailboats: [] } } ]

Bước 6 $ project - Sử dụng project để làm phẳng Bản đồ đối tượng của các phép nối

Chúng ta có thể sử dụng dự án để chọn tất cả dữ liệu hiện có và làm phẳng Bản đồ đối tượng của các kết quả nối thành một Mảng duy nhất.

  { '$project':
     // keys with the value 'true' will be included
     { name: true,
       license: true,
       classes: true,
       _id: true,
       watercraftContexts: true,
       __v: true,
       watercrafts:            // Re-assigns value of watercrafts
        { '$setUnion':         // Accepts an array of arrays to flatten
           [
             '$watercrafts.ships',
             '$watercrafts.yatches',
             '$watercrafts.sailboats'
           ]
        }
     }
  }
$ project Kết quả

Kết quả của $project ở trên sẽ thay thế watercrafts đối tượng với một mảng phẳng của watercrafts , nhưng điều quan trọng cần lưu ý là vẫn có các bản ghi trùng lặp của Captain nơi phù hợp với nhiều cách tra cứu khác nhau. Chúng ta sẽ tổng hợp lại chúng trong bước tiếp theo.

[ { _id: ObjectId('5f7bea8d79dfe25bf3cb9695'),
    name: 'CAPTAIN_SAIL',
    classes: [ 'sail' ],
    license: 'WC-1',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb9689'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb9689'),
         class: 'sail',
         name: 'Gone with the Wind',
         __v: 0 } ] },
  { _id: ObjectId('5f7bea8d79dfe25bf3cb9696'),
    name: 'CAPTAIN_YATCH',
    classes: [ 'yatch' ],
    license: 'WC-2',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb968a'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb968a'),
         class: 'yatch',
         name: 'Liquid Gold',
         __v: 0 } ] },
  { _id: ObjectId('5f7bea8d79dfe25bf3cb9697'),
    name: 'CAPTAIN_SHIP',
    classes: [ 'ship' ],
    license: 'WC-3',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb968b'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb968b'),
         class: 'ship',
         name: 'Jenny',
         __v: 0 } ] },
  { _id: ObjectId('5f7bea8d79dfe25bf3cb969b'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb9692'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb9692'),
         class: 'sail',
         name: 'Swell Shredder',
         __v: 0 } ] },
  { _id: ObjectId('5f7bea8d79dfe25bf3cb969b'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb9693'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb9693'),
         class: 'yatch',
         name: 'Audrey',
         __v: 0 } ] },
  { _id: ObjectId('5f7bea8d79dfe25bf3cb969b'),
    name: 'CAPTAIN_SAIL_YATCH_SHIP',
    classes: [ 'sail', 'yatch', 'ship' ],
    license: 'WC-7',
    watercraftContexts:
     { _id: ObjectId('5f7bea8d79dfe25bf3cb9694'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    watercrafts:
     [ { _id: ObjectId('5f7bea8d79dfe25bf3cb9694'),
         class: 'ship',
         name: 'Jenny IV',
         __v: 0 } ] } ]

Bước 7 $ thư giãn và $ nhóm

Chúng tôi $unwind để bây giờ chúng ta có thể nhóm tất cả watercrafts thuộc cùng một Captain . Chúng tôi cũng phải sử dụng $mergeObjects để tạm thời lưu trữ dữ liệu bổ sung từ Captain tập hợp theo một biến tạm thời mới để chuẩn bị cho các giai đoạn cuối cùng.

  { '$unwind': '$watercrafts' },
  { '$group':
     { _id: '$_id',
       data:
        { '$mergeObjects':
           { name: '$name',
             license: '$license',
             classes: '$classes',
             watercraftContexts: '$watercraftContexts',
             __v: '$__v' } },
       watercrafts: { '$push': '$watercrafts' } } }
$unwind$group Kết quả

Bây giờ chúng tôi thực sự đang đến một nơi nào đó. Chúng tôi đã giảm chuyển đổi xuống Captain 4 ban đầu của chúng tôi s và làm phẳng các liên kết của chúng tôi thành một mảng duy nhất.

[ { _id: ObjectId('5f7bed5e271dd95c306c25a4'),
    data:
     { name: 'CAPTAIN_SHIP',
       license: 'WC-3',
       classes: [ 'ship' ],
       watercraftContexts:
        { _id: ObjectId('5f7bed5e271dd95c306c2598'),
          watercraftType: 'Ship',
          ref: 'ships' },
       __v: 0 },
    watercrafts:
     [ { _id: ObjectId('5f7bed5e271dd95c306c2598'),
         class: 'ship',
         name: 'Jenny',
         __v: 0 } ] },
  { _id: ObjectId('5f7bed5e271dd95c306c25a8'),
    data:
     { name: 'CAPTAIN_SAIL_YATCH_SHIP',
       license: 'WC-7',
       classes: [ 'sail', 'yatch', 'ship' ],
       watercraftContexts:
        { _id: ObjectId('5f7bed5e271dd95c306c25a1'),
          watercraftType: 'Ship',
          ref: 'ships' },
       __v: 0 },
    watercrafts:
     [ { _id: ObjectId('5f7bed5e271dd95c306c259f'),
         class: 'sail',
         name: 'Swell Shredder',
         __v: 0 },
       { _id: ObjectId('5f7bed5e271dd95c306c25a0'),
         class: 'yatch',
         name: 'Audrey',
         __v: 0 },
       { _id: ObjectId('5f7bed5e271dd95c306c25a1'),
         class: 'ship',
         name: 'Jenny IV',
         __v: 0 } ] },
  { _id: ObjectId('5f7bed5e271dd95c306c25a2'),
    data:
     { name: 'CAPTAIN_SAIL',
       license: 'WC-1',
       classes: [ 'sail' ],
       watercraftContexts:
        { _id: Object('5f7bed5e271dd95c306c2596'),
          watercraftType: 'Sailboat',
          ref: 'sailboats' },
       __v: 0 },
    watercrafts:
     [ { _id: ObjectId('5f7bed5e271dd95c306c2596'),
         class: 'sail',
         name: 'Gone with the Wind',
         __v: 0 } ] },
  { _id: ObjectId('5f7bed5e271dd95c306c25a3'),
    data:
     { name: 'CAPTAIN_YATCH',
       license: 'WC-2',
       classes: [ 'yatch' ],
       watercraftContexts:
        { _id: ObjectId('5f7bed5e271dd95c306c2597'),
          watercraftType: 'Yatch',
          ref: 'yatches' },
       __v: 0 },
    watercrafts:
     [ { _id: ObjectId('5f7bed5e271dd95c306c2597'),
         class: 'yatch',
         name: 'Liquid Gold',
         __v: 0 } ] } ]

Bước 8 $ ReplaceRoot và $ project

Tất cả những gì chúng tôi còn lại là hợp nhất data của chúng tôi vào thư mục gốc của mỗi bản ghi và xóa biến tạm thời data

  // Merges 'data' into the root of each record
  { '$replaceRoot': { newRoot: { '$mergeObjects': [ '$data', '$$ROOT' ] } } },
  // Use $project to remove data (include only the fields we want)
  { '$project':
     { name: true,
       license: true,
       classes: true,
       _id: true,
       watercraftContexts: true,
       __v: true,
       watercrafts: true } 
  }
$ ReplaceRoot &$ project Kết quả

Bây giờ chúng tôi có kết quả mà chúng tôi đặt ra cho ... Một Captain với một loạt các loại liên kết hỗn hợp watercrafts

[ 
  { name: 'CAPTAIN_SAIL_YATCH_SHIP',
    license: 'WC-7',
    classes: [ 'sail', 'yatch', 'ship' ],
    watercraftContexts:
     { _id: ObjectId('5f7bf3b3680b375ca1755ea6'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    _id: ObjectId('5f7bf3b3680b375ca1755ead'),
    watercrafts:
     [ { _id: ObjectId('5f7bf3b3680b375ca1755ea4'),
         class: 'sail',
         name: 'Swell Shredder',
         __v: 0 },
       { _id: ObjectId('5f7bf3b3680b375ca1755ea5'),
         class: 'yatch',
         name: 'Audrey',
         __v: 0 },
       { _id: ObjectId('5f7bf3b3680b375ca1755ea6'),
         class: 'ship',
         name: 'Jenny IV',
         __v: 0 } ] },
  { name: 'CAPTAIN_SAIL',
    license: 'WC-1',
    classes: [ 'sail' ],
    watercraftContexts:
     { _id: ObjectId('5f7bf3b3680b375ca1755e9b'),
       watercraftType: 'Sailboat',
       ref: 'sailboats' },
    __v: 0,
    _id: ObjectId('5f7bf3b3680b375ca1755ea7'),
    watercrafts:
     [ { _id: ObjectId('5f7bf3b3680b375ca1755e9b'),
         class: 'sail',
         name: 'Gone with the Wind',
         __v: 0 } ] },
  { name: 'CAPTAIN_YATCH',
    license: 'WC-2',
    classes: [ 'yatch' ],
    watercraftContexts:
     { _id: ObjectId('5f7bf3b3680b375ca1755e9c'),
       watercraftType: 'Yatch',
       ref: 'yatches' },
    __v: 0,
    _id: ObjectId('5f7bf3b3680b375ca1755ea8'),
    watercrafts:
     [ { _id: ObjectId('5f7bf3b3680b375ca1755e9c'),
         class: 'yatch',
         name: 'Liquid Gold',
         __v: 0 } ] },
  { name: 'CAPTAIN_SHIP',
    license: 'WC-3',
    classes: [ 'ship' ],
    watercraftContexts:
     { _id: ObjectId('5f7bf3b3680b375ca1755e9d'),
       watercraftType: 'Ship',
       ref: 'ships' },
    __v: 0,
    _id: ObjectId('5f7bf3b3680b375ca1755ea9'),
    watercrafts:
     [ { _id: ObjectId('5f7bf3b3680b375ca1755e9d'),
         class: 'ship',
         name: 'Jenny',
         __v: 0 } ] } ]

Và bạn đã có nó ... chỉ mất 2 ngày để tìm ra điều này. Tôi hy vọng nó giúp bạn tiết kiệm thời gian nếu bạn đang cố gắng liên kết tổng hợp tương tự. Chúc bạn viết mã vui vẻ!

Đường ống cuối cùng

[ 
  { '$match':
     { _id:
        { '$in':
           [ ObjectId('5f7bf3b3680b375ca1755ea9'),
             ObjectId('5f7bf3b3680b375ca1755ea7'),
             ObjectId('5f7bf3b3680b375ca1755ea8'),
             ObjectId('5f7bf3b3680b375ca1755ead')
           ]
        }
     }
  },
  { '$unwind': '$watercraftContexts' },
  { '$lookup':
     { from: 'ships',
       localField: 'watercraftContexts._id',
       foreignField: '_id',
       as: 'watercrafts.ships' } },
  { '$unwind': '$watercraftContexts' },
  { '$lookup':
     { from: 'yatches',
       localField: 'watercraftContexts._id',
       foreignField: '_id',
       as: 'watercrafts.yatches' } },
  { '$unwind': '$watercraftContexts' },
  { '$lookup':
     { from: 'sailboats',
       localField: 'watercraftContexts._id',
       foreignField: '_id',
       as: 'watercrafts.sailboats' } },
  { '$project':
     { name: true,
       license: true,
       classes: true,
       _id: true,
       watercraftContexts: true,
       __v: true,
       watercrafts:
        { '$setUnion':
           [ '$watercrafts.ships',
             '$watercrafts.yatches',
             '$watercrafts.sailboats' ] } } },
  { '$unwind': '$watercrafts' },
  { '$group':
     { _id: '$_id',
       data:
        { '$mergeObjects':
           { name: '$name',
             license: '$license',
             classes: '$classes',
             watercraftContexts: '$watercraftContexts',
             __v: '$__v' } },
       watercrafts: { '$push': '$watercrafts' } } },
  { '$replaceRoot': { newRoot: { '$mergeObjects': [ '$data', '$$ROOT' ] } } },
  { '$project':
     { name: true,
       license: true,
       classes: true,
       _id: true,
       watercraftContexts: true,
       __v: true,
       watercrafts: true } }
]



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Tổng hợp MongoDB để thêm các tháng còn thiếu giữa hai ngày sau khi nhóm vào trường ngày

  2. MongoDB nhanh nhất trên Azure!

  3. Làm thế nào để đổi tên tên trường trong Spring-mongodb khi chèn dữ liệu?

  4. thực tiễn tốt nhất để đồng bộ hóa dữ liệu trong nodejs

  5. 2 cách xóa cơ sở dữ liệu trong MongoDB