首页 > 解决方案 > 使用 mongoose 查找特定文档之前和之后创建的 10 个文档

问题描述

我是一个没有经验的程序员,我对猫鼬还是很陌生。如果我在问一个愚蠢的问题,请饶了我。

假设我有 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;
                }
            });
            }
        });
    }
});

我还没有尝试过它是否有效,但它显然不是最好的解决方案(一个可怕的解决方案)并且可以被认为是回调地狱。

如果有更多经验和知识的人可以帮助我解决这个问题,将不胜感激。

标签: mongoose

解决方案


在 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

您也可以使用聚合在一个请求中完成所有三个查询,但它有点复杂。这将返回您通过 _id 查询的文档,其中包含两个额外的数组字段beforeDocsafterDocs.

示例: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}
    ]
  }},
])

推荐阅读