链接此查询会引发错误

时间:2016-04-08 22:31:29

标签: ruby-on-rails ruby mongoid

我正在尝试查询:

  1. 查找/获取对象(Coupon.code)
  2. 检查优惠券是否已过期(expires_at)
  3. 检查优惠券是否已用完。 (coupons_remaining)
  4. 我使用较新版本的ruby获得了一些语法,但它不能与我的2.2.1版本一起工作。我的语法是

      def self.get(code)
       where(code: normalize_code(code)).
       where("coupon_count > ? OR coupon_count IS NULL", 0).
       where("expires_at > ? OR expires_at IS NULL", Time.now).
       take(1)
     end
    

    这会引发错误wrong number of arguments (2 for 1),这是因为我的导轨似乎无法识别2个参数(" coupon_count>?或coupon_count IS NULL",0)所以我我试图改变它,但是当我把它们变成这样的东西时(在我心里感到可怕的错误)

    def self.get(code)
     where(code: normalize_code(code)).
     where(coupon_count: self.coupon_count > 0 || self.coupon_count.nil? ).
     where(expires_at: self.expires_at > Time.now || self.expires_at.nil? ).
     take(1)
    end
    

    我得到undefined method `coupon_count' for Coupon:Class

    我缺乏想法可以帮助我在模型中获取此get方法的语法吗?顺便说一下,如果重要的话,我正在使用mongoid 5.1.0

2 个答案:

答案 0 :(得分:1)

您已经定义了一个类方法,因此在这种情况下self引用Coupon类而不是Coupon实例。

尝试以下方法:

 scope :not_expired, -> { where("expires_at > ? OR expires_at IS NULL", Time.now) }
 scope :previously_used, -> { where("coupon_count > 0 OR coupon_count IS NULL") }

 def self.get(code)
   previously_used.not_expired.find_by!(code: normalize_code(code))
 end

答案 1 :(得分:1)

我感觉到你的痛苦。在MongoDB中组合OR和AND有点乱,因为你根本就没有真正使用查询语言,你只是构建一个哈希。如果您可以将多个条件应用于同一字段,则会出现类似的并发症这就是为什么你不能像ActiveRecord那样包含类似SQL的片段。

例如,表达:

"coupon_count > ? OR coupon_count IS NULL", 0

你需要建立一个像:

这样的哈希
:$or => [
    { :coupon_count.gt => 0   },
    { :coupon_count    => nil }
]

但是如果你尝试添加另一个OR,你将覆盖现有的:$or密钥并引起混淆。相反,你需要知道会有多个OR并通过说:$and手动避免重复:

:$and => [
    {
        :$or => [
            { :coupon_count.gt => 0   },
            { :coupon_count    => nil }
        ]
    }, {
        :$or => [
            { :expires_at.gt => Time.now },
            { :expires_at    => nil      }
        ]
    }
]

然后直接添加code条件:

:code => normalize_code(code),
:$and => [ ... ]

这使整个事情成为一个相当可怕的怪物:

def self.get(code)
  where(
    :code => normalize_code(code),
    :$and => [
      {
        :$or => [
          { :coupon_count.gt => 0   },
          { :coupon_count    => nil }
        ]
      }, {
        :$or => [
          { :expires_at.gt => Time.now },
          { :expires_at    => nil      }
        ]
      }
    ]
  ).first
end

您也可以使用find_by(that_big_mess)代替where(that_big_mess).first。此外,如果您希望查询匹配多个文档,那么您可能希望添加order调用以确保获得所需的文档。您可以使用andor查询方法而不是单个哈希,但我怀疑它会使事情易于阅读,理解或维护。

我尽量避免使用MongoDB进行OR操作,因为查询会快速失去他们的小脑袋,并且你会留下一些你不想过多想念的恐怖魔法恐怖。您通常最好使用生成的字段预先计算部分查询(您必须维护并进行健全性检查以确保它们是正确的);例如,如果coupon_count为正数或nil,则可以添加另一个为真的字段,然后在before_validation更改时在coupon_count挂钩中更新该字段。