【问题标题】:How do I get the negation of a mongoid query?如何获得对 mongoid 查询的否定?
【发布时间】:2012-01-27 14:44:58
【问题描述】:

在我的应用中,我有以下查询:

Model.where(flagged: true, saved: false)

或者我可以使用Model.all(:conditions => {flagged: true, saved: false})

没关系。

现在我如何获得该查询的否定?即所有不满足flagged: true AND saved: false 的模型实例(相当于flagged != true OR saved != false

Model.excludes(flagged: true, saved: false) 返回满足flagged != true AND saved != false) 的实例

【问题讨论】:

  • 你还有问题吗?
  • @tyler - 感谢您的提问。不,我已经解决了这个问题。这并没有阻止我,只是意味着我的代码不能像我想要的那样优雅。
  • 哦,看看我的回答。我认为它准确地完成了您正在寻找的事情,无论哪种方式,都为解决它而欢呼。
  • @tyler - 谢谢,但是当我在罗素的回答中加入 cmets 时,我想知道在一般情况下是否有可能,而不仅仅是针对我的具体情况。我猜 mongoid 可以做布尔扩展,但从它的声音来看,Russell 会反对

标签: mongodb mongoid


【解决方案1】:

您需要下拉到 MongoDB rub​​y​​ 驱动程序来执行此操作。

如果我正确理解了这个问题,当您在 $ne 子句之间寻找 OR 并且没有方法时,Mongoid 的 exclude 命令会执行 AND。

这就是你想要的 shell:

find({$or: [{flagged: {$ne: true}}, {saved: {$ne: true}}]})

在 ruby​​ 中,该查询如下所示:

query = {"$or" => [{"flagged" => {"$ne" => true}}, {"saved" => {"$ne" => true}}]}

如果我没记错的话,你可以说:

Model.collection.find(query) 查询是我上面定义的文档,它应该可以工作。

【讨论】:

    【解决方案2】:

    你试过$nor运营商吗?

    Model.all(:conditions => { '$nor' => [ { flagged: true }, { saved: false } ]})
    

    更多信息:http://docs.mongodb.org/manual/reference/operator/query/nor/

    【讨论】:

      【解决方案3】:

      对于您在问题中使用的具体情况,您可以这样做:

      Model.any_of({ flagged: false, saved: true }, { flagged: true, saved: true }, { flagged: false, saved: false } )
      

      但是,正如您在 cmets 中所说,您实际上是在寻找通用解决方案。 AFAIK 在 Mongoid 或 MongoDB 中无法做到这一点。

      原因很可能在于您无法在 MongoDB 查询中进行连接。例如,获取查询否定的传统 SQL 方法可能是:

      SELECT * FROM mytable t 
      WHERE t.id NOT IN ( SELECT t2.id FROM mytable t2 WHERE t2.condition = true )
      

      或者,为了避免 N+1 选择问题

      SELECT t.*, t2.id FROM mytable t
      OUTER JOIN mytable t2 ON ( t1.id AND t2.condition = true )
      WHERE t2.id = NULL
      

      这两者都依赖于以某种方式连接两个选择,而在 Mongo 中你不能这样做。

      唯一的另一种方法是像我一样以某种方式颠倒逻辑以获得上述对您的具体示例的答案。我认为让 Mongo 自动执行此操作是一个非常糟糕的主意,因为您最终会生成生成任意复杂查询的代码,您将无法控制并且无法优化。

      【讨论】:

      • 是的,你是。这让我得到了所有标记=假和保存=真的模型。我的查询的否定应该得到模型 where (flagged=false AND saved=true) OR (flagged=true AND saved=true) OR (flagged=false AND saved=false)
      • 我明白了,我的错误。我已经用应该工作的东西更新了我的答案;如果我想到任何更简洁或更高效的东西,我会用它来更新它。
      • 谢谢。这应该可行,但我正在寻找查询否定的一般答案(或者被告知 mongoid 不支持它)。如果我想要否定具有 N 个参数且 N 不小的查询,它不会很好地扩展。
      • 我想你会发现 Mongoid 不支持它,因为除了自己构建反向查询之外,AFAIK 无法使用 MongoDB 来实现它。你不能在 Mongo 中进行连接,所以我能想到的唯一 standard 方法是运行你的查询,然后对它返回的所有键执行 not in 查询。
      • 好的,谢谢,但我不明白它与连接有什么关系。这是布尔逻辑扩展。
      【解决方案4】:

      我发现我可以使用 Javascript expression syntax 来做到这一点

      所以Model.where(flagged: true, saved: false)的否定-可以表示为Model.where("this.flagged == true && this.saved == false")

      Model.where("!(this.flagged == true && this.saved == false)")
      

      正如 Russell 的评论所暗示的,这比使用本地查询语言效率低,但就我的目的而言,这不是问题,所以我现在将其标记为正确 - 但对于未来的读者,请记住对性能的影响。

      如果有人可以给出仅使用本机查询语言的答案,而无需进行显式的布尔逻辑扩展,我将其标记为正确(也许这在 Mongodb/Mongoid 的未来版本中是可能的 - 如果可以的话'现在还不行。)

      【讨论】:

      • 这对性能非常不利,应尽可能避免。
      • 千万不要这样做,Javascript 表达式不能使用索引。你应该只在查询只能用内置运算符表示时才使用它们(它可以)
      • “从不”?当然,这取决于具体情况。在我的情况下,性能不是问题,因为数据集的大小适中,并且将保持不变。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-25
      • 1970-01-01
      • 1970-01-01
      • 2012-01-06
      • 1970-01-01
      • 2014-05-19
      相关资源
      最近更新 更多