【问题标题】:mongoose sorting documents by a specific values from the document猫鼬按文档中的特定值对文档进行排序
【发布时间】:2020-08-10 02:16:03
【问题描述】:

我正在使用这种语法来过滤文档

const query = Model.find();
const filters = req.body;
if(filters.someValue){
    query.find().where('someValue').eq(filters.someValie);
}
...(imagine 40 more)

在执行此查询以查找所有文档之前,我想按我将确定的特定顺序对其进行排序

if(filters.sort){
    here the sort need to be applied - before execution.
}

我在数据库中获得了一些具有四个可选值的字段,并且我想将顺序附加到每个值(需要应用排序)。 假设值可以是:

"A", "B", "C", "D"

我希望文档排序的顺序:

{value:"A",order:3}, {value:"B", order:2}, {value:"C", order:4}, {value:"D", order:1}

并在应用排序后 - 执行查询。 问题是我在网上找不到任何关于此的内容,而我唯一尝试过的(与排序和条件聚合) - 没有奏效。 代码:

      SomeModel.aggregate([
    { "$project" : {
      "document": "$$ROOT",
        "order" : {
            "$cond" : {
                if : { "$eq" : ["$someField", "D"] }, then : 1,
                else  : { "$cond" : {
                    "if" : { "$eq" : ["$someField", "B"] }, then : 2, 
                    else  : { "if" : { "$eq" : ["$someField", "A"]}, then: 3, 
                    else : { "if" : { "$eq" : ["$someField", "C"]}, then: 4
                        }
                      }
                    }
                }
            }
        }
    }}, 
    {"$sort" : {"order" : 1} }
]);

【问题讨论】:

  • 在触发之前实际上无法排序,需要在 JavaScript 代码中进行
  • 我一开始就这样做了,它对大多数情况都很好,问题是有时文档数量超过 1M 并且服务器崩溃并出现没有内存堆栈的错误.. ..
  • @KunalMukherjee 你确定我不能在执行前排序吗?
  • 您可以在发送到数据库之前使用.sort对代码(在内存中/阻塞事件循环)进行排序
  • 还有一个问题,我的每页限制为 100 个文档(我也在使用分页)

标签: javascript node.js mongodb mongoose


【解决方案1】:

我设法通过不同的方法修复它。 当我在数据库中插入文档时 - 我要索引的每个字段都会有另一个字段表示值的索引。 (假设字段名称是 course,他的值是 A、B、C、D - 我将添加名为 courseIndex 的字段,并按值映射索引 - A = 4、B = 1、C = 2、D = 3).

这样我可以根据我的条件实现排序:)

【讨论】:

    【解决方案2】:

    内部if/then/elses 似乎存在格式错误的问题。您实际上在第三个和第四个else 中缺少一些$cond 运算符。因此,您得到的 order 属性值不正确(一个带有 if/then/else 而不是数字的对象)。

    这个版本适合我:

    [
      {
        $project: {
          'document': '$$ROOT',
          order: {
            $cond: {
              if: {'$eq': ['$someField', 'D']}, then: 1,
              else: {
                '$cond': {
                  'if': {'$eq': ['$someField', 'B']}, then: 2,
                  else: {
                    '$cond': {
                      'if': {'$eq': ['$someField', 'A']}, then: 3,
                      else: {
                        '$cond': {'if': {'$eq': ['$someField', 'C']}, then: 4, else: 5}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      {$sort: {'order': 1}}
    ]
    

    但是,在这种情况下,我认为 $switch 运算符可能会更好,特别是如果您有更多可能的值(不仅仅是这 4 个)。

    aggregate([
      {
        $project: {
          'document': '$$ROOT',
          order: {
            $switch: {
              branches: [
                {case: {'$eq': ['$name', 'D']}, then: 1},
                {case: {'$eq': ['$name', 'B']}, then: 2},
                {case: {'$eq': ['$name', 'A']}, then: 3},
                {case: {'$eq': ['$name', 'C']}, then: 4},
              ],
              default: null
            }
          }
        }
      },
      {$sort: {'order': 1}}
    ])
    

    【讨论】:

    • 首先,感谢您的宝贵时间,其次 - 它没有工作(当我执行此聚合时没有任何反应)
    • 嗯...你能分享更多细节吗?我在一些生成的数据上运行它,它运行良好。也许在这一步之前有什么问题(你说你之前有一些过滤器)?另外,请确保设置正确的属性名称,而不是 $name(这是我的假数据中的一个属性)。
    • 当然我将 $name 更改为我的字段,我之前所做的只是过滤与查询语句匹配的内容(看看我的问题的顶部 - 我解释了我的工作. 你能告诉我 ot 工作时的样子吗?(我的意思是,从 exec 方法返回的文档是按此聚合排序的?)
    • 是的,文档按order升序排列。问题实际上可能是因为findaggregate 不能很好地配合使用。与其分别使用findaggregate,不如尝试在aggregate 中使用$match 运算符(docs.mongodb.com/manual/reference/operator/aggregation/match)进行过滤。更多详情请参见此处:stackoverflow.com/questions/42394902/…
    • 问题是过滤器是非常动态的(就像我说的,我有 40 个过滤器)我需要找到一种可以动态过滤的方法 - 然后按我想要的顺序对所有文档进行排序...
    猜你喜欢
    • 2020-12-02
    • 2015-10-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2020-12-18
    相关资源
    最近更新 更多