Rails mongoid regex on an Integer field

2019-02-20 05:53发布

问题:

I have some IDs 214001, 214002, 215001, etc...

From a searchbar, I want autocompletion with the ID

"214" should trigger autocompletion for IDs 214001, 214002

Apparently, I can't just do a

scope :by_number, ->(number){
    where(:number => /#{number.to_i}/i)
}

with mongoid. Anyone know a working way of matching a mongoid Integer field with a regex ?

This question had some clue, but how can I do this inside Rails ?

EDIT : The context is to be able to find a project by its integer ID or its short description :

scope :by_intitule, ->(regex){ 
    where(:intitule => /#{Regexp.escape(regex)}/i)
}
# TODO : Not working !!!!
scope :by_number, ->(numero){
    where(:number => /#{number.to_i}/i)
}
scope :by_name, ->(regex){ 
    any_of([by_number(regex).selector, by_intitule(regex).selector])
}

回答1:

The MongoDB solution from the linked question would be:

db.models.find({ $where: '/^124/.test(this.number)' })

Things that you hand to find map pretty much one-to-one to Mongoid:

where(:$where => "/^#{numero.to_i}/.test(this.number)")

The to_i call should make string interpolation okay for this limited case.

Keep in mind that this is a pretty horrific thing to do to your database: it can't use indexes, it will scan every single document in the collection, ...

You might be better off using a string field so that you can do normal regex matching. I'm pretty sure MongoDB will be able to use an index if you anchor your regex at the beginning too. If you really need it to be a number inside the database then you could always store it as both an Integer and a String field:

field :number,   :type => Integer
field :number_s, :type => String

and then have some hooks to keep :number_s up to date as :number changes. If you did this, your pattern matching scope would look at :number_s. Precomputing and duplicating data like this is pretty common with MongoDB so you shouldn't feel bad about it.



回答2:

The way to do a $where in mongoid is using Criteria#for_js

Something like this

Model.for_js("new RegExp(number).test(this.int_field)", number: 763)