1

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])
}
2
  • This number represents a project number. It is incremented by one for every new project, therefore I needed an integer behaviour. And I want my project managers to be able to find a project "by its number" Commented Mar 1, 2015 at 1:03
  • After reading more I think I understand what you mean. In my case, I can afford some poor performance solutions. We're only talking about ~50-100 projects per year so it should be fine. Commented Mar 1, 2015 at 1:25

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, I'll leave a TODO in my code so I remember to do something clean like what you suggest.
Should I just override the number= method so as to update both :number and :number_s ? Am I missing some hooks if I do only this ? (eg. is Model.update_attributes using the field= methods)
update_attributes should call the field= method. I'd probably use a before_validation hook to set number_s and maybe even add a validation to make sure that number and number_s agree with each other.
0

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)

1 Comment

This doesn't seem to work. Running Project.for_js("/numero/.test(this.int_field)", numero: 214).any? should return true because I have a model with numero 214001, yet it returns false

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.