【问题标题】:How to change result position based off parameter in a mongodb / mongoose query?如何根据 mongodb / mongoose 查询中的参数更改结果位置?
【发布时间】:2012-01-05 02:45:29
【问题描述】:

所以我使用 mongoose 和 node.js 来访问 mongodb 数据库。我想根据一个数字增加每个结果(如果没有增加,它们按创建的日期排序)。例如:

{ name: 'A',
  bump: 0 },

{ name: 'B',
  bump: 0 },

{ name: 'C',
  bump: 2 },

{ name: 'D',
  bump: 1 }

将按以下顺序检索:C、A、D、B。如何实现(无需遍历数据库中的每个条目)?

【问题讨论】:

  • 所以你想让它按照1、2、1、0排序?
  • 不,我希望结果“增加”那么多结果
  • 请举个例子...“我有 x 存储在数据库中。一个请求进来了。我希望它做 y...”
  • 我认为这是不言自明的,但在这里:你有一个类似的列表:a、b、c、d。 'c' 在数字字段上获得 +1。然后列表变为:a,c,b,d
  • 不,这个问题令人困惑。您的排序“规则”没有意义。用例是什么?

标签: javascript node.js mongodb mongoose


【解决方案1】:

试试这样的。存储一个跟踪总线程数的计数器,我们称之为thread_count,最初设置为0,因此在某处有一个类似于{thread_count:0} 的文档。

每次创建新线程时,首先使用{$inc : {thread_count:1}} 作为修饰符调用findAndModify() - 即,将计数器加1并返回其新值。

然后当你插入新线程时,使用计数器的新值作为其文档中某个字段的值,我们称之为post_order。

因此,您插入的每个文档每次都有一个大 1 的值。例如,您插入的前 3 个文档如下所示:

{name:'foo', post_order:1, created_at:... } // value of thread_count is at 1 {name:'bar', post_order:2, created_at:... } // value of thread_count is at 2 {name:'baz', post_order:3, created_at:... } // value of thread_count is at 3 等等

如此有效,您可以通过post_order 以升序查询和排序,它会按从旧到最新的顺序返回它们(或从最新到最旧的降序)。

然后,当线程被投票时,要在其排序顺序中“碰撞”线程,您可以在带有{$inc:{post_order:1}} 的文档上调用update()。这将按结果排序的顺序将其提前 1。如果两个线程的 post_order 值相同,created_at 将区分哪个线程先出现。所以你会按post_order, created_at排序。

您将希望在post_order 和created_at 上有一个索引。

【讨论】:

    【解决方案2】:

    假设你的代码是变量response(它是一个数组),那么我会这样做:

    response.sort(function(obj1, obj2){
      return obj2.bump - obj1.bump;
    });
    

    或者如果您还想考虑名称顺序:

    response.sort(function(obj1, obj2){
      var diff = obj2.bump - obj1.bump;
      var nameDiff = (obj2.name > obj1.name)?-1:((obj2.name < obj1.name)?1:0);
      return (diff == 0) ? nameDiff : diff;
    });
    

    【讨论】:

    • 您的第一个将返回 C D A B,而不是 C A D B。他希望文档根据凹凸移动 - A 和 B 都有 0 凹凸,因此它们保持在原处。 C 有 2 个凸起,因此它上升 2 个,高于 A,因此此时列表为 C A B D。但是 D 有 1 个凸起,所以它上升 1,高于 B,所以最终列表是 C A D B。
    • @Jed 我猜他写错了。而我的回答是将凹凸解释为“秩序”……
    • 这不会迭代列表吗?诚然,我不是 MongoDB 专家,但我不确定如何在不迭代的情况下对任何语言的列表进行排序。
    【解决方案3】:

    不是一个令人愉快的答案,但您要求的解决方案是不切实际的。这是我的建议:

    1. 将 OrderPosition 属性添加到您的对象而不是 Bump。

    2. 将“碰撞”视为一个事件。它最好表示为事件处理函数。当一个项目被业务逻辑中的任何触发器“碰撞”时,需要调整项目的集合。

      var currentOrder = this.OrderPosition
      this.OrderPosition = currentOrder - bump;  // moves your object up the list
      // write a foreach loop here, iterating every item AFTER the items unadjusted
      // order, +1 to move them all down the list one notch.    
      

    这确实需要遍历许多项目,我知道您正试图阻止这种情况,但我认为没有其他方法可以安全地确保您的项目订购的完整性 - 特别是相对于发生的其他拉取集合稍后在路上。

    【讨论】:

    • 我认为你的方法是正确的,但你的实现是关闭的。您所要做的就是与前面的项目交换位置。你不应该需要迭代列表,除非只是为了找到前一个项目。
    • @gilly3 如果它只是一个列表对象并且您在其中交换位置,那么您是正确的。但据我了解,持久集合中的每个项目都有一个顺序,如果有任何移动,则必须调整其他项目。通过字段将此值保留在对象本身上意味着需要更新每条记录。相当低效,但对这个问题了解不多,我无法提供更好的解决方案。 :)
    【解决方案4】:

    我认为您的文档架构不可能实现纯粹的基于查询的解决方案(我假设您有 createdDate 和 bump 字段)。相反,我建议使用一个名为 sortorder 的字段来跟踪您想要的检索顺序:

    1. sortorder 最初是创建时间戳。如果没有“颠簸”,则按此字段排序会给出正确的顺序。
    2. 如果出现“碰撞”,sortorder 将失效。所以只需更正sortorder 值:每次发生“碰撞”时,交换碰撞文档的sortorder 字段和直接位于它前面的文档。这实际上是按排序顺序“颠簸”了文档。
    3. 查询时,按sortorder排序。

    如果字段bump 和createdDate 没有在其他地方使用,您可以删除它们。


    顺便说一句,大多数社交网站不会根据投票数(或“碰撞”)直接操纵帖子的显示位置。相反,投票数用于计算分数。然后根据这个分数对帖子进行排序和显示。在您的情况下,您应该将createdDate 和bumps 组合成一个可以在查询中排序的分数。

    这个网站 (StackOverflow.com) 有一个相关的meta discussion,关于如何确定“热门”问题。我认为甚至有一个竞争来想出一个新的公式。元问题还分享了另外两个流行的社交新闻网站使用的公式:Y Combinator Hacker News 和 Reddit。

    【讨论】:

      猜你喜欢
      • 2016-02-23
      • 1970-01-01
      • 1970-01-01
      • 2019-05-31
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 2020-06-17
      • 2014-12-26
      相关资源
      最近更新 更多