복붙노트

[MONGODB] 종류 및 한도 가상 채울 몽구스

MONGODB

종류 및 한도 가상 채울 몽구스

나는 그 자산에 대한 가장 최근의 거래와 함께 자산의 집합을 검색하는 몽구스 쿼리를 작성하려합니다. 거래는 자산으로부터 분리 수거에 있습니다.

이를 위해, 첫째 나는 거래 자산을 연결하는 자산 모델에서 가상 배열을 만들었습니다.

schema.virtual('transactions', {
    ref: 'transaction',
    localField: '_id',
    foreignField: '_asset',
    justOne: false
})

그리고 내가 Node.js를에 .populate을 컨트롤러를 명시하여 쿼리 할 (: 어떤 시점에서 N 될 것 하드 코딩 "1 제한"참고)

exports.getList = function (req, res) {
    Model
        .find({}, { __v: 0 })
        .populate({
            path: 'transactions',
            options: { sort: { 'created_at': -1}, limit: 1},
        })
        .lean()
        .exec(function (err, model) {
            if (err)
                res.send(err);
            res.json(model);
        });
  }

내 테스트 시스템 및 각각에 대한 거래의 무리에서 3 개 자산으로, 그것은 처음 두 자산과 세 번째에 아무것도 오래된 트랜잭션을 반환합니다.

나는 "제한 : 1"을 제거하면 모든 트랜잭션을 반환, 그것은 세 가지 자산에 대한 적절하고 반환 거래를 정렬합니다.

나는이 버그로 실행하고 생각 :

https://github.com/Automattic/mongoose/issues/4321

우아한 해결 방법에 어떤 아이디어? 모든 트랜잭션을 반환하는 실행 가능한 장기적인 해결책이 될 수 없습니다.

해결법

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

    1.이것은 참으로 곱슬 문제입니다. 여기에서 기본은 여기에 기대처럼 작동하도록 설계되지 않은, 확실히 .populate ()가 아니라 "virtuals에 채워"입니다.

    이것은 참으로 곱슬 문제입니다. 여기에서 기본은 여기에 기대처럼 작동하도록 설계되지 않은, 확실히 .populate ()가 아니라 "virtuals에 채워"입니다.

    에센스 .populate ()에서 관련 데이터를 검색 할 수 MongoDB를 발급 다른 쿼리는 본질적이다. 이를 위해 그것은 기본적으로에 일치하는 대상은 "관련 분야"모든 값을 포함에 $에 쿼리를 실행합니다.

    은 "문제 4321"의 핵심 무엇은 "종류"와 "제한"요구가 인수와 같은 $로 제공 될 것으로 실제 쿼리 등의 옵션이 될 것 인 .aggregate () 문이 사실이라는 것이다 "각 키에 대한 그룹화 마지막 n 결과를 얻을"수. 이렇게하여 MongoDB에 현재 문제를 몽구스 어떤 사실이 아니며 현재로서는 사용할 수있는 작업으로 그룹 N 항목에 정말 실용적입니다.

    당신은 .aggregate ()를 사용하여 수동으로 나열 제공의 끝에서 입증 것을 주위에 작동하지만 물론 단지 실제적 경우 제한된 수의에의 할 수 있습니다.

      // Get latest transactions for each master
      Transaction.aggregate([
        { '$match': {
          '_asset': {
            '$in': masters.map(m => m._id)
          }
        }},
        { '$sort': { '_asset': 1, 'createdAt': -1 } },
        { '$group': {
          '_id': '$_asset',
          'amount': { '$first': '$amount' },
          'createdAt': { '$first': '$createdAt' },
          'updatedAt': { '$first': '$updatedAt' },
          'did': { '$first': '$_id' }
        }},
        { '$project': {
          '_id': '$did',
          '_asset': '$_id',
          'amount': 1,
          'createdAt': 1,
          'updatedAt': 1
        }}
      ])
    

    그것은 잘되지가 아니라 정말 성능이 좋은 솔루션,하지만 다른 유사한 대안보다 낫다. 나는 아직도 더 좋은 방법이 있지만 믿고있다.

    여기에 귀하의 경우에, 나는 많은 유사한 사례를 의심 할, 당신으로 인해 발생되는 배열의 잠재적 크기도 참조로 부모 문서 내에서 "전체"거래 목록을 포함하지 않습니다. "안티 패턴"이런 종류의 않도록 설계되어 조회 참으로 $ 무엇을 "가상 채우기"일반적이다.

    의 특정 사용의 경우 "최신 거래를 얻을"하지만, 어느 쪽도 그 중 실행 가능한 솔루션 없습니다. 둘은 본질적으로 "모든"거래보고 만 그들로부터 n 개의 결과를 검색 할 필요 때문에.

    여기에 "최신"또는 참으로 "가장 최근"의 경우는 실제로 실행 가능한 솔루션을 제공하기 위해 "한정"에서 (적어도 참조) "삽입"을 다시 떨어질 그래서. 제안은 정확히 그렇게, 부모 자체 내에서 거래의 "최근"목록을 유지하는 것입니다 그래서. 이렇게하면 같은 그 모습을 포함 시나리오에서 문서를 제공합니다 :

    {
            "_id" : ObjectId("5959e34adf833e1451a32661"),
            "__v" : 0,
            "name" : "One",
            "recent" : [
                    ObjectId("5959e34bdf833e1451a32676"),
                    ObjectId("5959e34bdf833e1451a32674"),
                    ObjectId("5959e34bdf833e1451a32672"),
                    ObjectId("5959e34bdf833e1451a32670"),
                    ObjectId("5959e34bdf833e1451a3266e")
            ]
    }
    

    이들은 "모든"관련 거래 있었으나 결국 "가장 최근"사람이 아니라는 것을 여기에 주목. 요점은 목적에 적합한 같은 "작은"목록을 유지하는 것입니다.

    이러한 방법으로, 당신은 직접 배열은 "최근"항목에 포함 떨어져 "부모"그냥 $ 슬라이스를 조회 할 수 있습니다. 리스팅 (listing)에서 나는이 같은 수행

    Master.find().select({ 'recent': { '$slice': 1 } })
    

    그 반환 서버에 다른 쿼리없이 배열에서 "최신"항목. 동시에이 배열 대신에 우리가 "앞에 추가"항목은 우리가 모든 것을 가지고 '거래'수집에 쓰기로 있기 때문에,이 경우의 "최신"입니다 :

    Transaction.create({ _asset: master._id, amount: data.amount })
      .then(transaction =>
        Master.update(
          { _id: transaction._asset },
          { "$push": {
            "recent": {
              "$each": [transaction._id],
              "$position": 0,
              "$slice": 5
            }
          }}
        )
    

    "첫 번째"항목 그래서 배열의 시작 부분에 "preprend"에 $ 위치로 수정 부모의 배열에 $ 푸시가 핵심 요소는 항상 관련 추가 할 수있는 "최신"거래입니다 부모의.

    그런 다음 $ 슬라이스 수정은 n 개의 항목 만의 한계에 "최근"배열을 유지하기 위해 여기에 사용됩니다. 은 "오래된"항목 목록 "밀려"할 수 있도록 새로운 항목이 추가 될 때.

    또 다른 실제 목적은 페이징 시나리오에서 "마스터"및 "거래"를 나열 할 때, 첫 번째 요청은 직접 "최근"배열을 사용할 수 있습니다 여기에 추가로 다음이있다. 그런 다음 새로운 "페이지"에 대한 추가 요청은 단순히 항목 $ 닌를 통해 "최근의"배열에 포함 된 필터링 할 수 있습니다 각 "페이지를 검색하는 연습을 페이징으로 제한 할 () 또는 대체"범위 "(일반 .skip 사용) "결과.

    전체의 모든 개념을 설명하기 위해 목록을보고 아래의 모든 생성 된 결과.

    데모 목록 :

    const async = require('async'),
          mongoose = require('mongoose'),
          Schema = mongoose.Schema;
    
    mongoose.set('debug',true);
    mongoose.Promise = global.Promise;
    
    mongoose.connect('mongodb://localhost/prepend');
    
    const transactionSchema = new Schema({
      _asset: { type: Schema.Types.ObjectId, ref: 'Master' },
      amount: Number
    },{
      timestamps: {
        createdAt: 'createdAt'
      }
    });
    
    
    const Transaction = mongoose.model('Transaction', transactionSchema);
    
    const masterSchema = new Schema({
      name: String,
      recent: [{ type: Schema.Types.ObjectId, ref: 'Transaction' }]
    });
    
    masterSchema.virtual('transactions', {
      ref: 'Transaction',
      localField: '_id',
      foreignField: '_asset',
      justOne: false
    });
    
    
    const Master = mongoose.model('Master', masterSchema);
    
    function log(data) {
      console.log(JSON.stringify(data, undefined, 2))
    }
    
    async.series(
      [
        // Clean data
        (callback) =>
          async.each(mongoose.models,(model,callback) =>
            model.remove({},callback),callback),
    
        // Create Masters
        (callback) =>
          Master.insertMany(['One','Two'].map( name => ({ name })),callback),
    
        // Add 10 transactions to each master
        (callback) =>
          async.each(['One','Two'],(name,callback) =>
            async.eachSeries(
              Array.apply(null,Array(10)).map((e,i) => ({ name, amount: i+1 })),
              (data,callback) => {
                Master.findOne({ name: data.name })
                  .then(master =>
                    Transaction.create({ _asset: master._id, amount: data.amount })
                  )
                  .then(transaction =>
                    Master.update(
                      { _id: transaction._asset },
                      { "$push": {
                        "recent": {
                          "$each": [transaction._id],
                          "$position": 0,
                          "$slice": 5
                        }
                      }}
                    )
                  )
                  .then(res => callback())
                  .catch(callback)
              },
              callback
            ),
          callback),
    
        // Show populated recent 1 entry only
        (callback) =>
          Master.find().select({ 'recent': { '$slice': 1 } })
            .populate('recent').exec((err,results) => {
            if (err) callback(err);
            log(results);
            callback();
          }),
    
        // Populate recent - page 1 then fetch next page
        (callback) =>
          async.waterfall(
            [
              (callback) =>
                Master.findOne({ name: 'One' }).populate('recent')
                  .lean()
                  .exec((err,master) => {
                    if (err) callback(err);
                    log(master);
                    callback(null,{
                      _asset: master._id,
                      exclude: master.recent.map( r => r._id )
                    });
                  }),
    
              (options,callback) =>
                Transaction.find({
                  _asset: options._asset,
                  _id: { '$nin': options.exclude }
                }).sort({ 'createdAt': -1 }).limit(5)
                .exec((err,transactions) => {
                  if (err) callback(err);
                  log(transactions)
                  callback();
                })
    
            ],
            callback
          ),
    
        // Issue 4321 - Fix - Manual populate with aggregate
        (callback) =>
          Master.find().select('-recent').exec()
            .then(masters => {
              // Get latest transactions for each master
              Transaction.aggregate([
                { '$match': {
                  '_asset': {
                    '$in': masters.map(m => m._id)
                  }
                }},
                { '$sort': { '_asset': 1, 'createdAt': -1 } },
                { '$group': {
                  '_id': '$_asset',
                  'amount': { '$first': '$amount' },
                  'createdAt': { '$first': '$createdAt' },
                  'updatedAt': { '$first': '$updatedAt' },
                  'did': { '$first': '$_id' }
                }},
                { '$project': {
                  '_id': '$did',
                  '_asset': '$_id',
                  'amount': 1,
                  'createdAt': 1,
                  'updatedAt': 1
                }}
              ]).exec((err,transactions) => {
                // Map latest transactions to master
                masters = masters.map(
                  m => Object.assign(
                    m.toObject(),
                    {
                      transactions: transactions.filter(
                        t => t._asset.toHexString() === m._id.toHexString()
                      )
                    }
                  )
                );
    
                log(masters);
                callback();
              })
            }).catch(callback)
    
      ],
      (err) => {
        if (err) throw err;
        mongoose.disconnect();
      }
    );
    

    데모 출력

    Mongoose: transactions.remove({}, {})
    Mongoose: masters.remove({}, {})
    Mongoose: masters.insertMany([ { __v: 0, name: 'One', _id: 5959e34adf833e1451a32661, recent: [] }, { __v: 0, name: 'Two', _id: 5959e34adf833e1451a32662, recent: [] } ], null)
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:14 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:14 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 1, _id: ObjectId("5959e34adf833e1451a32663"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 1, _id: ObjectId("5959e34adf833e1451a32664"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34adf833e1451a32664") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34adf833e1451a32663") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 2, _id: ObjectId("5959e34bdf833e1451a32665"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 2, _id: ObjectId("5959e34bdf833e1451a32666"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32666") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32665") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 3, _id: ObjectId("5959e34bdf833e1451a32667"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 3, _id: ObjectId("5959e34bdf833e1451a32668"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32668") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32667") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 4, _id: ObjectId("5959e34bdf833e1451a32669"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 4, _id: ObjectId("5959e34bdf833e1451a3266a"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266a") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32669") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 5, _id: ObjectId("5959e34bdf833e1451a3266b"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 5, _id: ObjectId("5959e34bdf833e1451a3266c"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266c") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266b") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 6, _id: ObjectId("5959e34bdf833e1451a3266d"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 6, _id: ObjectId("5959e34bdf833e1451a3266e"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266e") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266d") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 7, _id: ObjectId("5959e34bdf833e1451a3266f"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 7, _id: ObjectId("5959e34bdf833e1451a32670"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32670") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a3266f") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 8, _id: ObjectId("5959e34bdf833e1451a32671"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 8, _id: ObjectId("5959e34bdf833e1451a32672"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32672") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32671") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 9, _id: ObjectId("5959e34bdf833e1451a32673"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 9, _id: ObjectId("5959e34bdf833e1451a32674"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32674") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32673") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: masters.findOne({ name: 'Two' }, { fields: {} })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32662"), amount: 10, _id: ObjectId("5959e34bdf833e1451a32675"), __v: 0 })
    Mongoose: transactions.insert({ updatedAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), createdAt: new Date("Mon, 03 Jul 2017 06:25:15 GMT"), _asset: ObjectId("5959e34adf833e1451a32661"), amount: 10, _id: ObjectId("5959e34bdf833e1451a32676"), __v: 0 })
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32661") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32676") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.update({ _id: ObjectId("5959e34adf833e1451a32662") }, { '$push': { recent: { '$each': [ ObjectId("5959e34bdf833e1451a32675") ], '$slice': 5, '$position': 0 } } }, {})
    Mongoose: masters.find({}, { fields: { recent: { '$slice': 1 } } })
    Mongoose: transactions.find({ _id: { '$in': [ ObjectId("5959e34bdf833e1451a32676"), ObjectId("5959e34bdf833e1451a32675") ] } }, { fields: {} })
    [
      {
        "_id": "5959e34adf833e1451a32661",
        "__v": 0,
        "name": "One",
        "recent": [
          {
            "_id": "5959e34bdf833e1451a32676",
            "updatedAt": "2017-07-03T06:25:15.282Z",
            "createdAt": "2017-07-03T06:25:15.282Z",
            "_asset": "5959e34adf833e1451a32661",
            "amount": 10,
            "__v": 0
          }
        ]
      },
      {
        "_id": "5959e34adf833e1451a32662",
        "__v": 0,
        "name": "Two",
        "recent": [
          {
            "_id": "5959e34bdf833e1451a32675",
            "updatedAt": "2017-07-03T06:25:15.280Z",
            "createdAt": "2017-07-03T06:25:15.280Z",
            "_asset": "5959e34adf833e1451a32662",
            "amount": 10,
            "__v": 0
          }
        ]
      }
    ]
    Mongoose: masters.findOne({ name: 'One' }, { fields: {} })
    Mongoose: transactions.find({ _id: { '$in': [ ObjectId("5959e34bdf833e1451a32676"), ObjectId("5959e34bdf833e1451a32674"), ObjectId("5959e34bdf833e1451a32672"), ObjectId("5959e34bdf833e1451a32670"), ObjectId("5959e34bdf833e1451a3266e") ] } }, { fields: {} })
    {
      "_id": "5959e34adf833e1451a32661",
      "__v": 0,
      "name": "One",
      "recent": [
        {
          "_id": "5959e34bdf833e1451a32676",
          "updatedAt": "2017-07-03T06:25:15.282Z",
          "createdAt": "2017-07-03T06:25:15.282Z",
          "_asset": "5959e34adf833e1451a32661",
          "amount": 10,
          "__v": 0
        },
        {
          "_id": "5959e34bdf833e1451a32674",
          "updatedAt": "2017-07-03T06:25:15.264Z",
          "createdAt": "2017-07-03T06:25:15.264Z",
          "_asset": "5959e34adf833e1451a32661",
          "amount": 9,
          "__v": 0
        },
        {
          "_id": "5959e34bdf833e1451a32672",
          "updatedAt": "2017-07-03T06:25:15.216Z",
          "createdAt": "2017-07-03T06:25:15.216Z",
          "_asset": "5959e34adf833e1451a32661",
          "amount": 8,
          "__v": 0
        },
        {
          "_id": "5959e34bdf833e1451a32670",
          "updatedAt": "2017-07-03T06:25:15.195Z",
          "createdAt": "2017-07-03T06:25:15.195Z",
          "_asset": "5959e34adf833e1451a32661",
          "amount": 7,
          "__v": 0
        },
        {
          "_id": "5959e34bdf833e1451a3266e",
          "updatedAt": "2017-07-03T06:25:15.180Z",
          "createdAt": "2017-07-03T06:25:15.180Z",
          "_asset": "5959e34adf833e1451a32661",
          "amount": 6,
          "__v": 0
        }
      ]
    }
    Mongoose: transactions.find({ _id: { '$nin': [ ObjectId("5959e34bdf833e1451a32676"), ObjectId("5959e34bdf833e1451a32674"), ObjectId("5959e34bdf833e1451a32672"), ObjectId("5959e34bdf833e1451a32670"), ObjectId("5959e34bdf833e1451a3266e") ] }, _asset: ObjectId("5959e34adf833e1451a32661") }, { sort: { createdAt: -1 }, limit: 5, fields: {} })
    [
      {
        "_id": "5959e34bdf833e1451a3266c",
        "updatedAt": "2017-07-03T06:25:15.164Z",
        "createdAt": "2017-07-03T06:25:15.164Z",
        "_asset": "5959e34adf833e1451a32661",
        "amount": 5,
        "__v": 0
      },
      {
        "_id": "5959e34bdf833e1451a3266a",
        "updatedAt": "2017-07-03T06:25:15.135Z",
        "createdAt": "2017-07-03T06:25:15.135Z",
        "_asset": "5959e34adf833e1451a32661",
        "amount": 4,
        "__v": 0
      },
      {
        "_id": "5959e34bdf833e1451a32668",
        "updatedAt": "2017-07-03T06:25:15.080Z",
        "createdAt": "2017-07-03T06:25:15.080Z",
        "_asset": "5959e34adf833e1451a32661",
        "amount": 3,
        "__v": 0
      },
      {
        "_id": "5959e34bdf833e1451a32666",
        "updatedAt": "2017-07-03T06:25:15.039Z",
        "createdAt": "2017-07-03T06:25:15.039Z",
        "_asset": "5959e34adf833e1451a32661",
        "amount": 2,
        "__v": 0
      },
      {
        "_id": "5959e34adf833e1451a32664",
        "updatedAt": "2017-07-03T06:25:15.009Z",
        "createdAt": "2017-07-03T06:25:15.009Z",
        "_asset": "5959e34adf833e1451a32661",
        "amount": 1,
        "__v": 0
      }
    ]
    Mongoose: masters.find({}, { fields: { recent: 0 } })
    Mongoose: transactions.aggregate([ { '$match': { _asset: { '$in': [ 5959e34adf833e1451a32661, 5959e34adf833e1451a32662 ] } } }, { '$sort': { _asset: 1, createdAt: -1 } }, { '$group': { _id: '$_asset', amount: { '$first': '$amount' }, createdAt: { '$first': '$createdAt' }, updatedAt: { '$first': '$updatedAt' }, did: { '$first': '$_id' } } }, { '$project': { _id: '$did', _asset: '$_id', amount: 1, createdAt: 1, updatedAt: 1 } } ], {})
    [
      {
        "_id": "5959e34adf833e1451a32661",
        "__v": 0,
        "name": "One",
        "transactions": [
          {
            "amount": 10,
            "createdAt": "2017-07-03T06:25:15.282Z",
            "updatedAt": "2017-07-03T06:25:15.282Z",
            "_id": "5959e34bdf833e1451a32676",
            "_asset": "5959e34adf833e1451a32661"
          }
        ]
      },
      {
        "_id": "5959e34adf833e1451a32662",
        "__v": 0,
        "name": "Two",
        "transactions": [
          {
            "amount": 10,
            "createdAt": "2017-07-03T06:25:15.280Z",
            "updatedAt": "2017-07-03T06:25:15.280Z",
            "_id": "5959e34bdf833e1451a32675",
            "_asset": "5959e34adf833e1451a32662"
          }
        ]
      }
    ]
    
  2. from https://stackoverflow.com/questions/44877203/mongoose-populate-virtual-with-sort-and-limit by cc-by-sa and MIT license