Selection

Origin provides a DSL for selection of documents in MongoDB, and supports all operations that MongoDB provides. As you build your queries, you can always access the raw selector by calling Queryable#selector.

Standard

The following is a table of all selection operations and their corresponding MongoDB selector.

Operation Origin Selector
Queryable#all

Add $all selection. Documents must match all values provided in the array. Also can be written with: Queryable#all_in

queryable.all(field: [ 1, 2, 3 ])
queryable.all(field: [ /(1|2|3)/ ])
{ "field" => { "$all" => [ 1, 2, 3 ]}}
{ "field" => { "$all" => [ /(1|2|3)/ ]}}
Queryable#and

Add $and selection. Documents must match all the criteria provided.

queryable.and(
  { name: "Syd" }, { active: true }
)
{
  "$and" => [
    { "name" => "Syd" }, { "active" => true }
  ]
}
Queryable#between

Add $gte/$lte selection. Finds documents with values between the lower and upper bound of the range.

queryable.between(age: 18..30)
{ "age" => { "$gte" => 18, "$lte" => 30 }}
Queryable#elem_match

Add $elemMatch selection. Finds documents with arrays of values that match the provided expression.

queryable.elem_match(members: { name: "Syd" })
{ "members" => { "$elemMatch" => { "name" => "Syd" }}}
Queryable#exists

Add $exists selection. Matches documents based on whether a value for the field exists or not. Will match docs with nil values if set to true.

queryable.exists(name: true)
{ "name" => { "$exists" => true }}
Queryable#gt

Add $gt selection. Matches documents who's field is greater than the provided value.

queryable.gt(age: 18)
{ "age" => { "$gt" => 18 }}
Queryable#gte

Add $gte selection. Matches documents who's field is greater than or equal to the provided value.

queryable.gte(age: 18)
{ "age" => { "$gte" => 18 }}
Queryable#in

Add $in selection. Matches documents who's field contains a value that is in the array, similar to a SQL IN. Also can be written as: Queryable#any_in.

queryable.in(name: [ "Syd", "Nancy" ])
{ "name" => { "$in" => [ "Syd", "Nancy" ]}}
Queryable#lt

Add $lt selection. Matches documents who's field is less than the provided value.

queryable.lt(age: 18)
{ "age" => { "$lt" => 18 }}
Queryable#lte

Add $lte selection. Matches documents who's field is less than or equal to the provided value.

queryable.lte(age: 18)
{ "age" => { "$lte" => 18 }}
Queryable#max_distance

Add $maxDistance selection. This can only be used in conjunction with near.

queryable.
  near(location: [ 20, 20 ]).
  max_distance(location: 0.5)
{
  "location" => {
    "$near" => [ 20, 20 ], "$maxDistance" => 0.5
  }
}
Queryable#mod

Add $mod selection. Matches documents who's field matches the modulo value.

queryable.mod(field: [ 10, 1 ])
{ "field" => { "$mod" => [ 10, 1 ]}}
Queryable#ne

Add $ne selection. Matches documents who's field is not equal to the provided value.

queryable.ne(name: "Nancy")
{ "name" => { "$ne" => "Nancy" }}
Queryable#near

Add $near selection. Matches documents who's geo location is near the provided coordinates.

queryable.near(location: [ 23.1, 12.1 ])
{ "location" => { "$near" => [ 23.1, 12.1 ] }}
Queryable#near_sphere

Add $nearSphere selection. Matches documents who's geo location is near the provided coordinates using spherical algorithms.

queryable.near_sphere(location: [ 23.1, 12.1 ])
{ "location" => { "$nearSphere" => [ 23.1, 12.1 ] }}
Queryable#nin

Add $nin selection. Matches documents who's field does not match values in the provided array.

queryable.nin(name: [ "Dave", "Martin" ])
{ "name" => { "$nin" => [ "Dave", "Martin" ] }}
Queryable#nor

Add $nor selection. Matches documents who do not match at least one of the provided criteria.

queryable.nor(
  { name: "Martin" }, { name: "Dave" }
)
{
  "$nor" => [
    { "name" => "Martin" }, { "name" => "Dave" }
  ]
}
Queryable#or

Add $or selection. Matches documents who match at least one of the provided criteria.

queryable.or(
  { name: "Martin" }, { name: "Dave" }
)
{
  "$or" => [
    { "name" => "Martin" }, { "name" => "Dave" }
  ]
}
Queryable#where

Add $where selection or standard document matching. If provided a string, we assume this is javascript and use $where. When a hash is provided this is a standard selection.

queryable.where(name: "Syd")
queryable.where("this.name == 'Syd'")
{ "name" => "Syd" }
{ "$where" => "this.name == 'Syd'" }
Queryable#with_size

Add $size selection. Matches documents who's array field has the exact size of the provided value. This is named with_size not to conflict with Ruby's Enumerable#size or Symbol#size.

queryable.with_size(members: 3)
{ "members" => { "$size" => 3 }}
Queryable#with_type

Add $type selection. Matches documents who's field is of the provided BSON type. See BSON Types for a complete list.

queryable.with_type(name: 2)
{ "name" => { "$type" => 2 }}
Queryable#within_box

Adds $within/$box selection. Matches documents that have geo locations inside the provided box.

queryable.within_box(
  location: [[ 1, 10 ], [ 10, 1 ]]
)
{
  "location" => {
    "$within" => { "$box" => [[ 1, 10 ], [ 10, 1 ]]}
  }
}
Queryable#within_circle

Adds $within/$center selection. Matches documents that have geo locations inside the provided circle with a radius.

queryable.within_circle(
  location: [[ 1, 10 ], 0.5 ]
)
{
  "location" => {
    "$within" => { "$center" => [[ 1, 10 ], 0.5 ]}
  }
}
Queryable#within_polygon

Adds $within/$polygon selection. Matches documents that have geo locations inside the provided polygon.

queryable.within_polygon(
  location: [
    [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]
  ]
)
{
  "location" => {
    "$within" => {
      "$polygon" => [
        [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]
      ]
    }
  }
}
Queryable#within_spherical_circle

Adds $within/$centerSphere selection. Matches documents that have geo locations inside the provided sphere with a radius.

queryable.within_spherical_circle(
  location: [[ 1, 10 ], 0.5 ]
)
{
  "location" => {
    "$within" => { "$centerSphere" => [[ 1, 10 ], 0.5 ]}
  }
}

Negation

You can negate any selection by placing a not immediately in front of the selection you want to invert. This will add a $not clause to the query.

Note that $not clauses can only be applied to other operators. See the official $not documentation for more information.

queryable.not.gt(age: 50)
queryable.selector #=> { "age" => { "$not" => { "$gt" => 50 }}}

Symbol Operators

As a convenience in where queries, Mongoid provides methods on symbol that generate more complex MongoDB operations. All symbol methods are listed in the following table, with their corresponding selectors.

Operation Origin Selector
Symbol#all

Add $all selection. Documents must match all values provided in the array.

queryable.where(:field.all => [ 1, 2, 3 ])
{ "field" => { "$all" => [ 1, 2, 3 ]}}
Symbol#elem_match

Add $elemMatch selection. Finds documents with arrays of values that match the provided expression.

queryable.where(
  :members.elem_match => { name: "Syd" }
)
{
  "members" => {
    "$elemMatch" => { "name" => "Syd" }
  }
}
Symbol#exists

Add $exists selection. Matches documents based on whether a value for the field exists or not. Will match docs with nil values if set to true.

queryable.where(:name.exists => true)
{ "name" => { "$exists" => true }}
Symbol#gt

Add $gt selection. Matches documents who's field is greater than the provided value.

queryable.where(:age.gt => 18)
{ "age" => { "$gt" => 18 }}
Symbol#gte

Add $gte selection. Matches documents who's field is greater than or equal to the provided value.

queryable.where(:age.gte => 18)
{ "age" => { "$gte" => 18 }}
Symbol#in

Add $in selection. Matches documents who's field contains a value that is in the array, similar to a SQL IN.

queryable.where(:name.in => [ "Syd", "Nancy" ])
{ "name" => { "$in" => [ "Syd", "Nancy" ]}}
Symbol#lt

Add $lt selection. Matches documents who's field is less than the provided value.

queryable.where(:age.lt => 18)
{ "age" => { "$lt" => 18 }}
Symbol#lte

Add $lte selection. Matches documents who's field is less than or equal to the provided value.

queryable.where(:age.lte => 18)
{ "age" => { "$lte" => 18 }}
Symbol#mod

Add $mod selection. Matches documents who's field matches the modulo value.

queryable.where(:field.mod => [ 10, 1 ])
{ "field" => { "$mod" => [ 10, 1 ]}}
Symbol#ne

Add $ne selection. Matches documents who's field is not equal to the provided value.

queryable.where(:name.ne => "Nancy")
{ "name" => { "$ne" => "Nancy" }}
Symbol#near

Add $near selection. Matches documents who's geo location is near the provided coordinates.

queryable.where(:location.near => [ 23.1, 12.1 ])
{ "location" => { "$near" => [ 23.1, 12.1 ] }}
Symbol#near_sphere

Add $nearSphere selection. Matches documents who's geo location is near the provided coordinates using spherical algorithms.

queryable.where(
  :location.near_sphere => [ 23.1, 12.1 ]
)
{ "location" => { "$nearSphere" => [ 23.1, 12.1 ] }}
Symbol#nin

Add $nin selection. Matches documents who's field does not match values in the provided array.

queryable.where(:name.nin => [ "Dave", "Martin" ])
{ "name" => { "$nin" => [ "Dave", "Martin" ] }}
Symbol#with_size

Add $size selection. Matches documents who's array field has the exact size of the provided value. This is named with_size not to conflict with Ruby's Enumerable#size or Symbol#size.

queryable.where(:members.with_size => 3)
{ "members" => { "$size" => 3 }}
Symbol#with_type

Add $type selection. Matches documents who's field is of the provided BSON type. See BSON Types for a complete list.

queryable.where(:name.with_type => 2)
{ "name" => { "$type" => 2 }}
Symbol#within_box

Adds $within/$box selection. Matches documents that have geo locations inside the provided box.

queryable.where(
  :location.within_box => [[ 1, 10 ], [ 10, 1 ]]
)
{
  "location" => {
    "$within" => { "$box" => [[ 1, 10 ], [ 10, 1 ]]}
  }
}
Symbol#within_circle

Adds $within/$center selection. Matches documents that have geo locations inside the provided circle with a radius.

queryable.where(
  :location.within_circle => [[ 1, 10 ], 0.5 ]
)
{
  "location" => {
    "$within" => { "$center" => [[ 1, 10 ], 0.5 ]}
  }
}
Symbol#within_polygon

Adds $within/$polygon selection. Matches documents that have geo locations inside the provided polygon.

queryable.where(
  :location.within_polygon => [
    [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]
  ]
)
{
  "location" => {
    "$within" => {
      "$polygon" => [
        [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]
      ]
    }
  }
}
Symbol#within_spherical_circle

Adds $within/$centerSphere selection. Matches documents that have geo locations inside the provided sphere with a radius.

queryable.where(
  :location.within_spherical_circle =>
    [[ 1, 10 ], 0.5 ]
)
{
  "location" => {
    "$within" => { "$centerSphere" => [[ 1, 10 ], 0.5 ]}
  }
}

Merge Strategies

Explicit Merging

The selection API also provides merge strategies for cases you want to override the default behaviour with specific methods that expect array values. The available strategies are *intersect, override, and union* and are used by chaining the name of the strategy before calling any method. For example, to override the default intersection behaviour of #in:

Band.in(name: [ "Depeche Mode" ]).union.in(name: [ "New Order" ])

This translates to the following selector.

{ "name" => { "$in" => [ "Depeche Mode", "New Order" ] }}

The default behaviour for the array methods are:

  • Queryable#all - defaults to union.
  • Queryable#in - defaults to intersect.
  • Queryable#nin - defaults to intersect.

The available strategies are:

  • Queryable#intersect Performs an intersection of existing and new array.
  • Queryable#override Overwrites the old array with the new.
  • Queryable#union Performs a union of the existing and new array.

Automatic Merging

When using the normal Origin DSL, criterion on the same field with different operators will automatically be merged into a complex selector on the common field. For example:

likeable = Band.gt(likes: 100).lt(likes: 1000).ne(likes: 500)
likeable.selector #=> { "likes" => { "$gt" => 100, "$lt" => 1000, "$ne" => 500 }}

Note that this works only when using the DSL methods, but not currently when using the symbol operators in a where clause.

likeable = Band.where(:likes.gt => 100, :likes.lt => 1000, :likes.ne => 500)
likeable.selector #=> { "likes" => { "$ne" => 500 }}