Skip to content

Commit

Permalink
MONGOID-5453 Add .none_of query method (#5524)
Browse files Browse the repository at this point in the history
* "none_of" query method

* update docs and release notes

* fix underline for header
  • Loading branch information
jamis committed Jan 20, 2023
1 parent 5ca8a18 commit 025efc1
Show file tree
Hide file tree
Showing 4 changed files with 490 additions and 2 deletions.
16 changes: 15 additions & 1 deletion docs/reference/queries.txt
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ conditions are added to the criteria:
Band.where(name: 1).or(name: 2).selector
# => {"$or"=>[{"name"=>"1"}, {"name"=>"2"}]}

``any_of``, ``nor`` and ``not`` behave similarly, with ``not`` producing
``any_of``, ``none_of``, ``nor`` and ``not`` behave similarly, with ``not`` producing
different query shapes as described below.

When ``and``, ``or`` and ``nor`` logical operators are used, they
Expand Down Expand Up @@ -425,6 +425,20 @@ The conditions are hoisted to the top level if possible:
# => {"label"=>/Trust/, "name"=>"Astral Projection"}


.. _none-of:

``none_of`` Behavior
--------------------

``none_of`` adds a negated disjunction ("nor") built from its arguments to
the existing conditions in the criteria. For example:

.. code-block:: ruby

Band.where(label: /Trust/).none_of({name: 'Astral Projection'}, {name: /Best/})
# => {"label"=>/Trust/, "$nor"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]}


``not`` Behavior
----------------

Expand Down
28 changes: 27 additions & 1 deletion docs/release-notes/mongoid-8.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,30 @@ example:
# => <Band _id: 633c74113282a438a15d2b56, name: "Death Cab For Cutie">

See the section on :ref:`Hash Assignment on Embedded Associations <hash-assignment>`
for more details
for more details


Added ``none_of`` Query Method
------------------------------

With the addition of ``none_of``, Mongoid 8.1 allows queries to exclude
conditions in bulk. The emitted query will encapsulate the specified
criteria in a ``$nor`` operation. For example:

.. code:: ruby

class Building
include Mongoid::Document
field :city, type: String
field :height, type: Integer
field :purpose, type: String
field :occupancy, type: Integer
end

Building.where(city: 'Portland').
none_of(:height.lt => 100,
:purpose => 'apartment',
:occupancy.gt => 2500)

This would query all buildings in Portland, excluding apartments, buildings less than
100 units tall, and buildings with an occupancy greater than 2500 people.
29 changes: 29 additions & 0 deletions lib/mongoid/criteria/queryable/selectable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,35 @@ def not(*criteria)
end
key :not, :override, "$not"

# Negate the arguments, constraining the query to only those documents
# that do NOT match the arguments.
#
# @example Exclude a single criterion.
# selectable.none_of(name: /Bob/)
#
# @example Exclude multiple criteria.
# selectable.none_of(name: /Bob/, country: "USA")
#
# @example Exclude multiple criteria as an array.
# selectable.none_of([{ name: /Bob/ }, { country: "USA" }])
#
# @param [ [ Hash | Criteria ]... ] *criteria The key/value pair
# matches or Criteria objects to negate.
#
# @return [ Selectable ] The new selectable.
def none_of(*criteria)
criteria = _mongoid_flatten_arrays(criteria)
return dup if criteria.empty?

exprs = criteria.map do |criterion|
_mongoid_expand_keys(
criterion.is_a?(Selectable) ?
criterion.selector : criterion)
end

self.and('$nor' => exprs)
end

# Creates a disjunction using $or from the existing criteria in the
# receiver and the provided arguments.
#
Expand Down
Loading

0 comments on commit 025efc1

Please sign in to comment.