【问题标题】:Mongoose/MongoDB: $in and .sort()Mongoose/MongoDB:$in 和 .sort()
【发布时间】:2017-05-18 22:00:18
【问题描述】:

我使用了一个 API,它每天跟踪 50 个成员在游戏中的数据,并使用 mongoose 将 JSON 转换为集合中的单个文档。几天之间有一致的数据,例如每个成员的标签(游戏中成员的 id),但有不同的数据(不同的分数等)。每个文档都有一个createdAt 属性。

我想找到每个成员的最新文档,因此有一个包含每个成员标签的数组。

我目前使用以下查询来查找标签匹配的所有文档,但是它们返回的是 所有 文档,而不仅仅是一个。如何将文档排序/限制为最近的文档,同时将其保留为一个查询(或者是否有更多“mongodb 方式”)?

memberTags = [1,2,3,4,5];
ClanMember.find({
    'tag': {
        $in: memberTags
    }
}).lean().exec(function(err, members) {
    res.json(members);
});

谢谢

【问题讨论】:

  • 可以通过聚合来完成。

标签: javascript node.js mongodb mongoose


【解决方案1】:

好的,首先,让我们使用findOne(),这样您就只能从请求中获取一个文档 然后按照最新的文档排序,你可以使用.sort({elementYouWantToSort: -1})(-1表示你想从最新到最旧排序,1从最旧到最新排序) 我建议在 _id 上使用这个函数,它已经包含了文档的创建日期 这给了我们以下要求:

ClanMember.findOne({
    'tag': {
        $in: memberTags
    }
}).sort({_id: -1}).lean().exec(function(err, members) {
    res.json(members);
});

【讨论】:

  • 不会只返回 1 个文档,而不是每个标签的最新文档吗?
【解决方案2】:

您可以通过聚合框架进行查询。您的查询将涉及pipeline,它具有处理输入文档的阶段,以便为您提供所需的结果。在您的情况下,管道将有一个 $match 阶段,它充当初始过滤器的查询。 $match 使用标准 MongoDB 查询,因此您仍然可以使用 $in 进行查询。

下一步是按createdAt 字段对过滤后的文档进行排序。这是使用 $sort 运算符完成的。

前面的管道阶段涉及聚合有序文档以返回每个组的顶部文档。 $group 运算符和 $first 累加器是使这成为可能的运算符。

综上所述,您可以运行以下聚合操作来获得所需的结果:

memberTags = [1,2,3,4,5];
ClanMember.aggregate([
    { "$match": { "tag": { "$in": memberTags } } },
    { "$sort": { "tag": 1, "createdAt: -1 " } },
    {
        "$group": {
            "_id": "$tag",
            "createdAt": { "$first": "$createdAt" } /*,
            include other necessary fields as appropriate
            using the $first operator e.g.
            "otherField1": { "$first": "$otherField1" },
            "otherField2": { "$first": "$otherField2" },
            ...

            */
        }
    }
]).exec(function(err, members) {
    res.json(members);
});

或者使用find() 调整您当前的查询,以便您可以对两个字段进行排序,即tag(升序)和createdAt(降序)属性。然后,您可以使用 limit 选择前 5 个文档,如下所示:

memberTags = [1,2,3,4,5];
ClanMember.find(
    { 'tag': { $in: memberTags } }, // query
    {}, // projection
    { // options
        sort: { 'createdAt': -1, 'tag': 1 },
        limit: memberTags.length, 
        skip: 0
    }
).lean().exec(function(err, members) {
    res.json(members);
});

memberTags = [1,2,3,4,5];
ClanMember.find({
    'tag': {
        $in: memberTags
    }
}).sort('-createdAt tag')
  .limit(memberTags.length)
  .lean()
  .exec(function(err, members) {
    res.json(members);
});

【讨论】:

  • 太棒了,虽然aggregate 查询有效,但我不想重复查询返回所需的字段,但是您对find() 查询的调整完美无缺。谢谢!
  • 不用担心,很高兴这有效。最初,我只能想到一个aggregate 的方法,只是为了发现一些事情不需要考虑太多:)
猜你喜欢
  • 2013-01-16
  • 2012-05-21
  • 2011-05-30
  • 2017-07-04
  • 2012-12-03
  • 2016-07-15
  • 2017-07-01
  • 2019-12-16
  • 2021-12-17
相关资源
最近更新 更多