Skip to content

MONGOID-4998 Drop support for the :id_sort option and only accept positional argument #5362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/reference/queries.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1301,9 +1301,10 @@ Mongoid also has some helpful methods on criteria.

* - ``Criteria#first|last``

*Finds a single document given the provided criteria. This automatically adds a sort on _id.
Opt out of adding the id sort with the {id_sort: :none} option. This option is deprecated -
please call ``take`` instead. Get a list of documents by passing in a limit argument.*
*Finds a single document given the provided criteria. Get a list of
documents by passing in a limit argument. This method automatically adds
a sort on _id. This can cause performance issues, so if the sort is
undesirable, Criteria#take can be used instead.*

-
.. code-block:: ruby
Expand Down
7 changes: 7 additions & 0 deletions docs/release-notes/mongoid-8.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -640,3 +640,10 @@ Deprecated the ``geoHaystack``, ``geoSearch`` Options
-----------------------------------------------------

The ``geoHaystack`` and ``geoSearch`` options on indexes have been deprecated.


Support Dropped for the ``:id_sort`` Option on ``#first/last``
--------------------------------------------------------------

Support for the ``:id_sort`` option on the ``#first`` and ``#last`` options has
been dropped. These methods now only except a limit as a positional argument.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def build(base, object, type = nil, selected_fields = nil)
private

def execute_query(object, type)
query_criteria(object, type).limit(1).first(id_sort: :none)
query_criteria(object, type).take
end

def query_criteria(object, type)
Expand Down
28 changes: 10 additions & 18 deletions lib/mongoid/association/referenced/has_many/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,19 +240,15 @@ def any?(*args)
# @note Automatically adding a sort on _id when no other sort is
# defined on the criteria has the potential to cause bad performance issues.
# If you experience unexpected poor performance when using #first or #last,
# use the option { id_sort: :none }.
# Be aware that #first/#last won't guarantee order in this case.
# use #take instead.
# Be aware that #take won't guarantee order.
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The first document found.
def first(limit_or_opts = nil)
def first(limit = nil)
_loaded.try(:values).try(:first) ||
_added[(ul = _unloaded.try(:first, limit_or_opts)).try(:_id)] ||
_added[(ul = _unloaded.try(:first, limit)).try(:_id)] ||
ul ||
_added.values.try(:first)
end
Expand Down Expand Up @@ -329,20 +325,16 @@ def in_memory
# @note Automatically adding a sort on _id when no other sort is
# defined on the criteria has the potential to cause bad performance issues.
# If you experience unexpected poor performance when using #first or #last,
# use the option { id_sort: :none }.
# Be aware that #first/#last won't guarantee order in this case.
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
# use #take instead.
# Be aware that #take won't guarantee order.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The last document found.
def last(limit_or_opts = nil)
def last(limit = nil)
_added.values.try(:last) ||
_loaded.try(:values).try(:last) ||
_added[(ul = _unloaded.try(:last, limit_or_opts)).try(:_id)] ||
_added[(ul = _unloaded.try(:last, limit)).try(:_id)] ||
ul
end

Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/association/referenced/has_one/buildable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def query_criteria(object, base)
end

def execute_query(object, base)
query_criteria(object, base).limit(1).first(id_sort: :none)
query_criteria(object, base).take
end

def with_polymorphic_criterion(criteria, base)
Expand Down
25 changes: 10 additions & 15 deletions lib/mongoid/contextual/memory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,14 @@ def exists?
# @example Get the first document.
# context.first
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The first document.
def first(limit_or_opts = nil)
if limit_or_opts.nil? || limit_or_opts.is_a?(Hash)
eager_load([documents.first]).first
def first(limit = nil)
if limit
eager_load(documents.first(limit))
else
eager_load(documents.first(limit_or_opts))
eager_load([documents.first]).first
end
end
alias :one :first
Expand Down Expand Up @@ -166,18 +165,14 @@ def inc(incs)
# @example Get the last document.
# context.last
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The last document.
def last(limit_or_opts = nil)
if limit_or_opts.nil? || limit_or_opts.is_a?(Hash)
eager_load([documents.last]).first
def last(limit = nil)
if limit
eager_load(documents.last(limit))
else
eager_load(documents.last(limit_or_opts))
eager_load([documents.last]).first
end
end

Expand Down
44 changes: 13 additions & 31 deletions lib/mongoid/contextual/mongo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,30 +250,19 @@ def find_one_and_delete
# @note Automatically adding a sort on _id when no other sort is
# defined on the criteria has the potential to cause bad performance issues.
# If you experience unexpected poor performance when using #first or #last
# and have no sort defined on the criteria, use the option { id_sort: :none }.
# Be aware that #first/#last won't guarantee order in this case.
# and have no sort defined on the criteria, use #take instead.
# Be aware that #take won't guarantee order.
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The first document.
def first(limit_or_opts = nil)
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
def first(limit = nil)
if cached? && cache_loaded?
return limit ? documents.first(limit) : documents.first
end
try_numbered_cache(:first, limit) do
if limit_or_opts.try(:key?, :id_sort)
Mongoid::Warnings.warn_id_sort_deprecated
end
sorted_view = view
if sort = view.sort || ({ _id: 1 } unless limit_or_opts.try(:fetch, :id_sort) == :none)
sorted_view = view.sort(sort)
end
if raw_docs = sorted_view.limit(limit || 1).to_a
sort = view.sort || { _id: 1 }
if raw_docs = view.sort(sort).limit(limit || 1).to_a
process_raw_docs(raw_docs, limit)
end
end
Expand Down Expand Up @@ -362,23 +351,18 @@ def initialize(criteria)
# @note Automatically adding a sort on _id when no other sort is
# defined on the criteria has the potential to cause bad performance issues.
# If you experience unexpected poor performance when using #first or #last
# and have no sort defined on the criteria, use the option { id_sort: :none }.
# Be aware that #first/#last won't guarantee order in this case.
# and have no sort defined on the criteria, use #take instead.
# Be aware that #take won't guarantee order.
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The last document.
def last(limit_or_opts = nil)
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
def last(limit = nil)
if cached? && cache_loaded?
return limit ? documents.last(limit) : documents.last
end
res = try_numbered_cache(:last, limit) do
with_inverse_sorting(limit_or_opts) do
with_inverse_sorting do
if raw_docs = view.limit(limit || 1).to_a
process_raw_docs(raw_docs, limit)
end
Expand Down Expand Up @@ -742,11 +726,9 @@ def apply_option(name)
#
# @example Apply the inverse sorting params to the given block
# context.with_inverse_sorting
def with_inverse_sorting(opts = {})
Mongoid::Warnings.warn_id_sort_deprecated if opts.try(:key?, :id_sort)

def with_inverse_sorting
begin
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts.try(:fetch, :id_sort) == :none )
if sort = criteria.options[:sort] || { _id: 1 }
@view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
end
yield
Expand Down
18 changes: 6 additions & 12 deletions lib/mongoid/contextual/none.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,29 +122,23 @@ def initialize(criteria)
# @example Get the first document in null context.
# context.first
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ nil ] Always nil.
def first(limit_or_opts = nil)
if !limit_or_opts.nil? && !limit_or_opts.is_a?(Hash)
[]
end
def first(limit = nil)
[] unless limit.nil?
end

# Always returns nil.
#
# @example Get the last document in null context.
# context.last
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ nil ] Always nil.
def last(limit_or_opts = nil)
if !limit_or_opts.nil? && !limit_or_opts.is_a?(Hash)
[]
end
def last(limit = nil)
[] unless limit.nil?
end

# Returns nil or empty array.
Expand Down
20 changes: 6 additions & 14 deletions lib/mongoid/findable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,11 @@ def find_by!(attrs = {})
# @example Find the first document.
# Person.first
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The first matching document.
def first(limit_or_opts = nil)
with_default_scope.first(limit_or_opts)
def first(limit = nil)
with_default_scope.first(limit)
end
alias :one :first

Expand All @@ -211,15 +207,11 @@ def first(limit_or_opts = nil)
# @example Find the last document.
# Person.last
#
# @param [ Integer | Hash ] limit_or_opts The number of documents to
# return, or a hash of options.
#
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
# Don't apply a sort on _id if no other sort is defined on the criteria.
# @param [ Integer ] limit The number of documents to return.
#
# @return [ Document ] The last matching document.
def last(limit_or_opts = nil)
with_default_scope.last(limit_or_opts)
def last(limit = nil)
with_default_scope.last(limit)
end
end
end
2 changes: 0 additions & 2 deletions lib/mongoid/warnings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ def warning(id, message)
end
end
end

warning :id_sort_deprecated, 'The :id_sort option has been deprecated. Use Mongo#take to get a document without a sort on _id.'
end
end

58 changes: 2 additions & 56 deletions spec/mongoid/association/referenced/has_many/enumerable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1237,33 +1237,6 @@
end
end

context 'when the id_sort option is none' do

let(:person) do
Person.create!
end

let(:criteria) do
Post.where(person_id: person.id)
end

let(:enumerable) do
described_class.new(criteria)
end

let!(:first_post) do
person.posts.create!(title: "One")
end

let!(:second_post) do
person.posts.create!(title: "Two")
end

it 'does not use the sort on id' do
expect(enumerable.first(id_sort: :none)).to eq(first_post)
end
end

context 'when including a limit' do

let(:person) do
Expand Down Expand Up @@ -1291,7 +1264,7 @@
end
end

context 'when the id_sort option is not provided' do
context 'when no parameters are provided' do

let(:person) do
Person.create!
Expand Down Expand Up @@ -1761,34 +1734,7 @@
end
end

context 'when the id_sort option is none' do

let(:person) do
Person.create!
end

let(:criteria) do
Post.where(person_id: person.id)
end

let(:enumerable) do
described_class.new(criteria)
end

let!(:first_post) do
person.posts.create!(title: "One")
end

let!(:second_post) do
person.posts.create!(title: "Two")
end

it 'does not use the sort on id' do
expect(enumerable.last(id_sort: :none)).to eq(first_post)
end
end

context 'when the id_sort option is not provided' do
context 'when no parameters are provided' do

let(:person) do
Person.create!
Expand Down
Loading