Найдите 10 документов, созданных до и после определенного документа с помощью mongoose

#mongoose

#мангуст

Вопрос:

Я неопытный программист, и я все еще новичок в mongoose. Избавьте меня, если я задаю глупый вопрос.

Допустим, у меня есть коллекция из более чем 100 документов. Я хочу указать один документ и найти 10 документов, созданных до и 10 документов, созданных после этого документа.

Одно из решений, которое я придумал, выглядит примерно так:

 let firstDoc;
let tenBefore;
let tenAfter;

// find the starting document
document.findById(id, function(err, foundDoc){
    if(err) {
        ...
    } else {
        firstDoc = foundDoc;

        // find the 10 documents before
        document
        .find({created_at: {$lt: foundDoc.created_at}})
        .limit(10)
        .exec(function(err, beforeDocs) {
            if(err) {...} else {
            tenBefore = beforeDocs;
            
            // find the 10 documents after
            document
            .find({created_at: {$gt: foundDoc.created_at}})
            .limit(10)
            .exec(function(err, afterDocs) {
                if(err) {...} else {
                tenAfter = afterDocs;
                }
            });
            }
        });
    }
});
  

Я еще не пробовал это, чтобы посмотреть, работает ли это вообще или нет, но это, очевидно, не лучшее решение (ужасное при этом) и может считаться адом обратного вызова.

Если кто-нибудь с большим опытом и знаниями может помочь мне с этой проблемой, я был бы очень признателен.

Ответ №1:

В ES7 вы можете очистить обратные вызовы с помощью async / await. Вы также можете запускать вторые запросы одновременно с Promise.all

 async function() {
  const foundDoc = await document.findById(id).catch(err => ...);
  const [beforeDocs, afterDocs] = await Promise.all([
    document
        .find({created_at: {$lt: foundDoc.created_at}})
        .sort({created_at: -1}) // sort descending to get latest 10
        .limit(10),
    document
        .find({created_at: {$gt: foundDoc.created_at}})
        .sort({created_at: 1}) // sort ascending to get earliest 10
        .limit(10),
  ]);
}
  

AsyncAwait:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Разрушение: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Promise.all:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Вы также можете использовать aggregate для выполнения всех трех запросов в одном запросе, но это немного сложнее. Это вернет документ, который вы запрашиваете по _id с двумя дополнительными полями массива beforeDocs и afterDocs .

Пример:https://mongoplayground.net/p/6KeNaCpaifO

 db.collection.aggregate([
  {$match: {
    _id: 5 // use mongoose.Types.ObjectId('YOUROBJECTID')
  }},
  {$lookup: {
    from: "collection",
    as: "beforeDocs",
    let: {
      "parent_created_at": "$created_at"
    },
    pipeline: [
      {$match: {
        // Need to use $expr to access parent created at date
        $expr: {$lt: ["$created_at", "$$parent_created_at"]}
      }},
      {$sort: {created_at: -1}},
      {$limit: 10}
    ]
  }},
  {$lookup: {
    from: "collection",
    as: "afterDocs",
    let: {
      "parent_created_at": "$created_at"
    },
    pipeline: [
      {$match: {
        $expr: {$gt: ["$created_at", "$$parent_created_at"]}
      }},
      {$sort: {created_at: 1}},
      {$limit: 10}
    ]
  }},
])