mongoid 3.0.23 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +253 -9
- data/LICENSE +1 -1
- data/README.md +4 -1
- data/lib/config/locales/en.yml +7 -6
- data/lib/mongoid.rb +18 -1
- data/lib/mongoid/atomic.rb +22 -20
- data/lib/mongoid/atomic/paths/embedded.rb +19 -5
- data/lib/mongoid/atomic/paths/root.rb +1 -1
- data/lib/mongoid/atomic/positionable.rb +73 -0
- data/lib/mongoid/attributes.rb +63 -1
- data/lib/mongoid/callbacks.rb +58 -4
- data/lib/mongoid/components.rb +8 -3
- data/lib/mongoid/config.rb +71 -23
- data/lib/mongoid/contextual.rb +2 -1
- data/lib/mongoid/contextual/aggregable/mongo.rb +27 -63
- data/lib/mongoid/contextual/atomic.rb +4 -3
- data/lib/mongoid/contextual/find_and_modify.rb +1 -1
- data/lib/mongoid/contextual/geo_near.rb +238 -0
- data/lib/mongoid/contextual/map_reduce.rb +12 -1
- data/lib/mongoid/contextual/memory.rb +36 -31
- data/lib/mongoid/contextual/mongo.rb +147 -91
- data/lib/mongoid/contextual/queryable.rb +25 -0
- data/lib/mongoid/copyable.rb +4 -1
- data/lib/mongoid/criteria.rb +23 -275
- data/lib/mongoid/criterion/findable.rb +179 -0
- data/lib/mongoid/criterion/modifiable.rb +191 -0
- data/lib/mongoid/criterion/scoping.rb +11 -6
- data/lib/mongoid/document.rb +7 -56
- data/lib/mongoid/equality.rb +66 -0
- data/lib/mongoid/errors/mongoid_error.rb +7 -3
- data/lib/mongoid/extensions/array.rb +13 -1
- data/lib/mongoid/extensions/date.rb +9 -2
- data/lib/mongoid/extensions/hash.rb +38 -2
- data/lib/mongoid/extensions/nil_class.rb +12 -0
- data/lib/mongoid/extensions/object.rb +24 -0
- data/lib/mongoid/extensions/string.rb +14 -2
- data/lib/mongoid/extensions/time.rb +4 -1
- data/lib/mongoid/fields.rb +49 -5
- data/lib/mongoid/fields/foreign_key.rb +12 -0
- data/lib/mongoid/fields/standard.rb +12 -0
- data/lib/mongoid/finders.rb +8 -0
- data/lib/mongoid/hierarchy.rb +19 -1
- data/lib/mongoid/indexes.rb +30 -4
- data/lib/mongoid/indexes/validators/options.rb +12 -2
- data/lib/mongoid/inspection.rb +2 -1
- data/lib/mongoid/matchers/strategies.rb +5 -5
- data/lib/mongoid/observer.rb +27 -36
- data/lib/mongoid/persistence.rb +42 -17
- data/lib/mongoid/persistence/atomic.rb +10 -5
- data/lib/mongoid/persistence/atomic/operation.rb +26 -9
- data/lib/mongoid/persistence/atomic/unset.rb +1 -1
- data/lib/mongoid/persistence/operations/embedded/insert.rb +5 -2
- data/lib/mongoid/persistence/operations/embedded/remove.rb +5 -2
- data/lib/mongoid/persistence/operations/update.rb +7 -3
- data/lib/mongoid/railties/database.rake +12 -19
- data/lib/mongoid/relations.rb +2 -0
- data/lib/mongoid/relations/accessors.rb +30 -8
- data/lib/mongoid/relations/binding.rb +5 -1
- data/lib/mongoid/relations/bindings/referenced/in.rb +1 -1
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +3 -3
- data/lib/mongoid/relations/counter_cache.rb +107 -0
- data/lib/mongoid/relations/embedded/batchable.rb +13 -4
- data/lib/mongoid/relations/embedded/many.rb +30 -1
- data/lib/mongoid/relations/macros.rb +2 -0
- data/lib/mongoid/relations/marshalable.rb +0 -1
- data/lib/mongoid/relations/metadata.rb +63 -11
- data/lib/mongoid/relations/options.rb +1 -0
- data/lib/mongoid/relations/proxy.rb +45 -2
- data/lib/mongoid/relations/referenced/in.rb +11 -2
- data/lib/mongoid/relations/referenced/many.rb +31 -3
- data/lib/mongoid/relations/referenced/many_to_many.rb +31 -3
- data/lib/mongoid/relations/referenced/one.rb +1 -1
- data/lib/mongoid/relations/targets/enumerable.rb +5 -1
- data/lib/mongoid/relations/touchable.rb +35 -6
- data/lib/mongoid/reloading.rb +5 -3
- data/lib/mongoid/scoping.rb +2 -2
- data/lib/mongoid/sessions.rb +57 -7
- data/lib/mongoid/sessions/factory.rb +22 -1
- data/lib/mongoid/threaded.rb +4 -30
- data/lib/mongoid/threaded/lifecycle.rb +12 -12
- data/lib/mongoid/timestamps.rb +1 -0
- data/lib/mongoid/timestamps/created.rb +2 -0
- data/lib/mongoid/timestamps/created/short.rb +19 -0
- data/lib/mongoid/timestamps/short.rb +10 -0
- data/lib/mongoid/timestamps/updated.rb +2 -0
- data/lib/mongoid/timestamps/updated/short.rb +19 -0
- data/lib/mongoid/validations.rb +2 -0
- data/lib/mongoid/validations/queryable.rb +2 -2
- data/lib/mongoid/validations/uniqueness.rb +1 -18
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/model/model_generator.rb +1 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +3 -0
- data/lib/rails/mongoid.rb +53 -29
- data/lib/support/ruby_version.rb +26 -0
- metadata +18 -7
@@ -4,6 +4,7 @@ require "mongoid/contextual/aggregable/mongo"
|
|
4
4
|
require "mongoid/contextual/command"
|
5
5
|
require "mongoid/contextual/eager"
|
6
6
|
require "mongoid/contextual/find_and_modify"
|
7
|
+
require "mongoid/contextual/geo_near"
|
7
8
|
require "mongoid/contextual/map_reduce"
|
8
9
|
|
9
10
|
module Mongoid
|
@@ -13,25 +14,10 @@ module Mongoid
|
|
13
14
|
include Aggregable::Mongo
|
14
15
|
include Atomic
|
15
16
|
include Eager
|
17
|
+
include Queryable
|
16
18
|
|
17
|
-
# @attribute [r] collection The collection to query against.
|
18
|
-
# @attribute [r] criteria The criteria for the context.
|
19
|
-
# @attribute [r] klass The klass for the criteria.
|
20
19
|
# @attribute [r] query The Moped query.
|
21
|
-
attr_reader :
|
22
|
-
|
23
|
-
# Is the enumerable of matching documents empty?
|
24
|
-
#
|
25
|
-
# @example Is the context empty?
|
26
|
-
# context.blank?
|
27
|
-
#
|
28
|
-
# @return [ true, false ] If the context is empty.
|
29
|
-
#
|
30
|
-
# @since 3.0.0
|
31
|
-
def blank?
|
32
|
-
!exists?
|
33
|
-
end
|
34
|
-
alias :empty? :blank?
|
20
|
+
attr_reader :query
|
35
21
|
|
36
22
|
# Is the context cached?
|
37
23
|
#
|
@@ -145,12 +131,15 @@ module Mongoid
|
|
145
131
|
# @example Do any documents exist for the context.
|
146
132
|
# context.exists?
|
147
133
|
#
|
134
|
+
# @note We don't use count here since Mongo does not use counted
|
135
|
+
# b-tree indexes, unless a count is already cached then that is
|
136
|
+
# used to determine the value.
|
137
|
+
#
|
148
138
|
# @return [ true, false ] If the count is more than zero.
|
149
139
|
#
|
150
140
|
# @since 3.0.0
|
151
141
|
def exists?
|
152
|
-
|
153
|
-
!query.dup.select(_id: 1).limit(1).entries.first.nil?
|
142
|
+
@exists ||= check_existence
|
154
143
|
end
|
155
144
|
|
156
145
|
# Run an explain on the criteria.
|
@@ -196,12 +185,63 @@ module Mongoid
|
|
196
185
|
#
|
197
186
|
# @since 3.0.0
|
198
187
|
def first
|
199
|
-
|
200
|
-
|
201
|
-
|
188
|
+
if cached? && cache_loaded?
|
189
|
+
documents.first
|
190
|
+
else
|
191
|
+
with_sorting do
|
192
|
+
with_eager_loading(query.first)
|
193
|
+
end
|
194
|
+
end
|
202
195
|
end
|
203
196
|
alias :one :first
|
204
197
|
|
198
|
+
# Execute a $geoNear command against the database.
|
199
|
+
#
|
200
|
+
# @example Find documents close to 10, 10.
|
201
|
+
# context.geo_near([ 10, 10 ])
|
202
|
+
#
|
203
|
+
# @example Find with spherical distance.
|
204
|
+
# context.geo_near([ 10, 10 ]).spherical
|
205
|
+
#
|
206
|
+
# @example Find with a max distance.
|
207
|
+
# context.geo_near([ 10, 10 ]).max_distance(0.5)
|
208
|
+
#
|
209
|
+
# @example Provide a distance multiplier.
|
210
|
+
# context.geo_near([ 10, 10 ]).distance_multiplier(1133)
|
211
|
+
#
|
212
|
+
# @param [ Array<Float> ] coordinates The coordinates.
|
213
|
+
#
|
214
|
+
# @return [ GeoNear ] The GeoNear command.
|
215
|
+
#
|
216
|
+
# @since 3.1.0
|
217
|
+
def geo_near(coordinates)
|
218
|
+
GeoNear.new(collection, criteria, coordinates)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Invoke the block for each element of Contextual. Create a new array
|
222
|
+
# containing the values returned by the block.
|
223
|
+
#
|
224
|
+
# If the symbol field name is passed instead of the block, additional
|
225
|
+
# optimizations would be used.
|
226
|
+
#
|
227
|
+
# @example Map by some field.
|
228
|
+
# context.map(:field1)
|
229
|
+
#
|
230
|
+
# @exmaple Map with block.
|
231
|
+
# context.map(&:field1)
|
232
|
+
#
|
233
|
+
# @param [ Symbol ] field The field name.
|
234
|
+
#
|
235
|
+
# @return [ Array ] The result of mapping.
|
236
|
+
def map(field = nil, &block)
|
237
|
+
if block_given?
|
238
|
+
super(&block)
|
239
|
+
else
|
240
|
+
field = field.to_sym
|
241
|
+
criteria.only(field).map(&field.to_proc)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
205
245
|
# Create the new Mongo context. This delegates operations to the
|
206
246
|
# underlying driver - in Mongoid's case Moped.
|
207
247
|
#
|
@@ -230,8 +270,9 @@ module Mongoid
|
|
230
270
|
#
|
231
271
|
# @since 3.0.0
|
232
272
|
def last
|
233
|
-
|
234
|
-
|
273
|
+
with_inverse_sorting do
|
274
|
+
with_eager_loading(query.first)
|
275
|
+
end
|
235
276
|
end
|
236
277
|
|
237
278
|
# Get's the number of documents matching the query selector.
|
@@ -276,6 +317,25 @@ module Mongoid
|
|
276
317
|
MapReduce.new(collection, criteria, map, reduce)
|
277
318
|
end
|
278
319
|
|
320
|
+
# Pluck the single field values from the database. Will return duplicates
|
321
|
+
# if they exist and only works for top level fields.
|
322
|
+
#
|
323
|
+
# @example Pluck a field.
|
324
|
+
# context.pluck(:_id)
|
325
|
+
#
|
326
|
+
# @note This method will return the raw db values - it performs no custom
|
327
|
+
# serialization.
|
328
|
+
#
|
329
|
+
# @param [ String, Symbol ] field The field to pluck.
|
330
|
+
#
|
331
|
+
# @return [ Array<Object> ] The plucked values.
|
332
|
+
#
|
333
|
+
# @since 3.1.0
|
334
|
+
def pluck(field)
|
335
|
+
normalized = field.to_s
|
336
|
+
query.select(normalized => 1).map{ |doc| doc[normalized] }.compact
|
337
|
+
end
|
338
|
+
|
279
339
|
# Skips the provided number of documents.
|
280
340
|
#
|
281
341
|
# @example Skip the documents.
|
@@ -305,7 +365,10 @@ module Mongoid
|
|
305
365
|
if block_given?
|
306
366
|
super(&block)
|
307
367
|
else
|
308
|
-
|
368
|
+
# update the criteria
|
369
|
+
@criteria = criteria.order_by(values)
|
370
|
+
apply_option(:sort)
|
371
|
+
self
|
309
372
|
end
|
310
373
|
end
|
311
374
|
|
@@ -314,7 +377,7 @@ module Mongoid
|
|
314
377
|
# @example Update the first matching document.
|
315
378
|
# context.update({ "$set" => { name: "Smiths" }})
|
316
379
|
#
|
317
|
-
# @param [ Hash ] attributes The new attributes for
|
380
|
+
# @param [ Hash ] attributes The new attributes for the document.
|
318
381
|
#
|
319
382
|
# @return [ nil, false ] False if no attributes were provided.
|
320
383
|
#
|
@@ -339,6 +402,24 @@ module Mongoid
|
|
339
402
|
|
340
403
|
private
|
341
404
|
|
405
|
+
# Checks if any documents exist in the database.
|
406
|
+
#
|
407
|
+
# @api private
|
408
|
+
#
|
409
|
+
# @example Check for document existsence.
|
410
|
+
# context.check_existence
|
411
|
+
#
|
412
|
+
# @return [ true, false ] If documents exist.
|
413
|
+
#
|
414
|
+
# @since 3.1.0
|
415
|
+
def check_existence
|
416
|
+
if cached? && cache_loaded?
|
417
|
+
!documents.empty?
|
418
|
+
else
|
419
|
+
@count ? @count > 0 : !query.dup.select(_id: 1).limit(1).entries.first.nil?
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
342
423
|
# Update the documents for the provided method.
|
343
424
|
#
|
344
425
|
# @api private
|
@@ -355,7 +436,7 @@ module Mongoid
|
|
355
436
|
def update_documents(attributes, method = :update)
|
356
437
|
return false unless attributes
|
357
438
|
attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
|
358
|
-
query.send(method, attributes.__consolidate__)
|
439
|
+
query.send(method, attributes.__consolidate__(klass))
|
359
440
|
end
|
360
441
|
|
361
442
|
# Apply the field limitations.
|
@@ -372,55 +453,32 @@ module Mongoid
|
|
372
453
|
end
|
373
454
|
end
|
374
455
|
|
375
|
-
# Apply the
|
456
|
+
# Apply the options.
|
376
457
|
#
|
377
458
|
# @api private
|
378
459
|
#
|
379
|
-
# @example Apply
|
380
|
-
# context.
|
460
|
+
# @example Apply all options.
|
461
|
+
# context.apply_options
|
381
462
|
#
|
382
|
-
# @since 3.
|
383
|
-
def
|
384
|
-
|
385
|
-
|
463
|
+
# @since 3.1.0
|
464
|
+
def apply_options
|
465
|
+
apply_fields
|
466
|
+
[ :hint, :limit, :skip, :sort, :batch_size, :max_scan ].each do |name|
|
467
|
+
apply_option(name)
|
386
468
|
end
|
387
469
|
end
|
388
470
|
|
389
|
-
# Apply
|
471
|
+
# Apply an option.
|
390
472
|
#
|
391
473
|
# @api private
|
392
474
|
#
|
393
|
-
# @example Apply the
|
394
|
-
# context.
|
395
|
-
#
|
396
|
-
# @since 3.0.0
|
397
|
-
def apply_limit
|
398
|
-
if spec = criteria.options[:limit]
|
399
|
-
query.limit(spec)
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
# Map the sort symbols to the correct MongoDB values.
|
404
|
-
#
|
405
|
-
# @example Apply the sorting params.
|
406
|
-
# context.apply_sorting
|
407
|
-
#
|
408
|
-
# @since 3.0.0
|
409
|
-
def apply_sorting
|
410
|
-
if spec = criteria.options[:sort]
|
411
|
-
query.sort(spec)
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
# Apply the hint option
|
416
|
-
#
|
417
|
-
# @example Apply the hint params.
|
418
|
-
# context.apply_hint
|
475
|
+
# @example Apply the skip option.
|
476
|
+
# context.apply_option(:skip)
|
419
477
|
#
|
420
|
-
# @since 3.
|
421
|
-
def
|
422
|
-
if spec = criteria.options[
|
423
|
-
query.
|
478
|
+
# @since 3.1.0
|
479
|
+
def apply_option(name)
|
480
|
+
if spec = criteria.options[name]
|
481
|
+
query.send(name, spec)
|
424
482
|
end
|
425
483
|
end
|
426
484
|
|
@@ -429,27 +487,39 @@ module Mongoid
|
|
429
487
|
#
|
430
488
|
# @api private
|
431
489
|
#
|
432
|
-
# @example Apply the id sorting params
|
433
|
-
# context.
|
490
|
+
# @example Apply the id sorting params to the given block
|
491
|
+
# context.with_sorting
|
434
492
|
#
|
435
493
|
# @since 3.0.0
|
436
|
-
def
|
437
|
-
|
438
|
-
|
494
|
+
def with_sorting
|
495
|
+
begin
|
496
|
+
unless criteria.options.has_key?(:sort)
|
497
|
+
query.sort(_id: 1)
|
498
|
+
end
|
499
|
+
yield
|
500
|
+
ensure
|
501
|
+
apply_option(:sort)
|
439
502
|
end
|
440
503
|
end
|
441
504
|
|
442
505
|
# Map the inverse sort symbols to the correct MongoDB values.
|
443
506
|
#
|
444
|
-
#
|
445
|
-
#
|
507
|
+
# @api private
|
508
|
+
#
|
509
|
+
# @example Apply the inverse sorting params to the given block
|
510
|
+
# context.with_inverse_sorting
|
446
511
|
#
|
447
512
|
# @since 3.0.0
|
448
|
-
def
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
513
|
+
def with_inverse_sorting
|
514
|
+
begin
|
515
|
+
if spec = criteria.options[:sort]
|
516
|
+
query.sort(Hash[spec.map{|k, v| [k, -1*v]}])
|
517
|
+
else
|
518
|
+
query.sort(_id: -1)
|
519
|
+
end
|
520
|
+
yield
|
521
|
+
ensure
|
522
|
+
apply_option(:sort)
|
453
523
|
end
|
454
524
|
end
|
455
525
|
|
@@ -524,20 +594,6 @@ module Mongoid
|
|
524
594
|
end
|
525
595
|
end
|
526
596
|
|
527
|
-
# Apply all the optional criterion.
|
528
|
-
#
|
529
|
-
# @example Apply the options.
|
530
|
-
# context.apply_options
|
531
|
-
#
|
532
|
-
# @since 3.0.0
|
533
|
-
def apply_options
|
534
|
-
apply_fields
|
535
|
-
apply_limit
|
536
|
-
apply_skip
|
537
|
-
apply_sorting
|
538
|
-
apply_hint
|
539
|
-
end
|
540
|
-
|
541
597
|
# If we are limiting results, we need to set the field limitations on a
|
542
598
|
# thread local to avoid overriding the default values.
|
543
599
|
#
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Contextual
|
4
|
+
module Queryable
|
5
|
+
|
6
|
+
# @attribute [r] collection The collection to query against.
|
7
|
+
# @attribute [r] criteria The criteria for the context.
|
8
|
+
# @attribute [r] klass The klass for the criteria.
|
9
|
+
attr_reader :collection, :criteria, :klass
|
10
|
+
|
11
|
+
# Is the enumerable of matching documents empty?
|
12
|
+
#
|
13
|
+
# @example Is the context empty?
|
14
|
+
# context.blank?
|
15
|
+
#
|
16
|
+
# @return [ true, false ] If the context is empty.
|
17
|
+
#
|
18
|
+
# @since 3.0.0
|
19
|
+
def blank?
|
20
|
+
!exists?
|
21
|
+
end
|
22
|
+
alias :empty? :blank?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/mongoid/copyable.rb
CHANGED
@@ -18,7 +18,10 @@ module Mongoid
|
|
18
18
|
#
|
19
19
|
# @return [ Document ] The new document.
|
20
20
|
def clone
|
21
|
-
|
21
|
+
# @note This next line is here to address #2704, even though having an
|
22
|
+
# _id and id field in the document would cause problems with Mongoid
|
23
|
+
# elsewhere.
|
24
|
+
attrs = clone_document.except("_id", "id")
|
22
25
|
self.class.new(attrs, without_protection: true)
|
23
26
|
end
|
24
27
|
alias :dup :clone
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "mongoid/criterion/inspection"
|
3
|
+
require "mongoid/criterion/findable"
|
3
4
|
require "mongoid/criterion/marshalable"
|
5
|
+
require "mongoid/criterion/modifiable"
|
4
6
|
require "mongoid/criterion/scoping"
|
5
7
|
|
6
8
|
module Mongoid
|
@@ -16,7 +18,9 @@ module Mongoid
|
|
16
18
|
include Contextual
|
17
19
|
include Origin::Queryable
|
18
20
|
include Criterion::Inspection
|
21
|
+
include Criterion::Findable
|
19
22
|
include Criterion::Marshalable
|
23
|
+
include Criterion::Modifiable
|
20
24
|
include Criterion::Scoping
|
21
25
|
|
22
26
|
attr_accessor :embedded, :klass
|
@@ -48,23 +52,6 @@ module Mongoid
|
|
48
52
|
entries.as_json(options)
|
49
53
|
end
|
50
54
|
|
51
|
-
# Build a document given the selector and return it.
|
52
|
-
# Complex criteria, such as $in and $or operations will get ignored.
|
53
|
-
#
|
54
|
-
# @example build the document.
|
55
|
-
# Person.where(:title => "Sir").build
|
56
|
-
#
|
57
|
-
# @example Build with selectors getting ignored.
|
58
|
-
# Person.where(:age.gt => 5).build
|
59
|
-
#
|
60
|
-
# @return [ Document ] A non-persisted document.
|
61
|
-
#
|
62
|
-
# @since 2.0.0
|
63
|
-
def build(attrs = {}, &block)
|
64
|
-
create_document(:new, attrs, &block)
|
65
|
-
end
|
66
|
-
alias :new :build
|
67
|
-
|
68
55
|
# Tells the criteria that the cursor that gets returned needs to be
|
69
56
|
# cached. This is so multiple iterations don't hit the database multiple
|
70
57
|
# times, however this is not advisable when working with large data sets
|
@@ -90,41 +77,6 @@ module Mongoid
|
|
90
77
|
options[:cache] == true
|
91
78
|
end
|
92
79
|
|
93
|
-
# Create a document in the database given the selector and return it.
|
94
|
-
# Complex criteria, such as $in and $or operations will get ignored.
|
95
|
-
#
|
96
|
-
# @example Create the document.
|
97
|
-
# Person.where(:title => "Sir").create
|
98
|
-
#
|
99
|
-
# @example Create with selectors getting ignored.
|
100
|
-
# Person.where(:age.gt => 5).create
|
101
|
-
#
|
102
|
-
# @return [ Document ] A newly created document.
|
103
|
-
#
|
104
|
-
# @since 2.0.0.rc.1
|
105
|
-
def create(attrs = {}, &block)
|
106
|
-
create_document(:create, attrs, &block)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Create a document in the database given the selector and return it.
|
110
|
-
# Complex criteria, such as $in and $or operations will get ignored.
|
111
|
-
# If validation fails, an error will be raised.
|
112
|
-
#
|
113
|
-
# @example Create the document.
|
114
|
-
# Person.where(:title => "Sir").create
|
115
|
-
#
|
116
|
-
# @example Create with selectors getting ignored.
|
117
|
-
# Person.where(:age.gt => 5).create
|
118
|
-
#
|
119
|
-
# @raise [ Errors::Validations ] on a validation error.
|
120
|
-
#
|
121
|
-
# @return [ Document ] A newly created document.
|
122
|
-
#
|
123
|
-
# @since 3.0.0
|
124
|
-
def create!(attrs = {}, &block)
|
125
|
-
create_document(:create!, attrs, &block)
|
126
|
-
end
|
127
|
-
|
128
80
|
# Get the documents from the embedded criteria.
|
129
81
|
#
|
130
82
|
# @example Get the documents.
|
@@ -162,24 +114,6 @@ module Mongoid
|
|
162
114
|
!!@embedded
|
163
115
|
end
|
164
116
|
|
165
|
-
# Execute the criteria or raise an error if no documents found.
|
166
|
-
#
|
167
|
-
# @example Execute or raise
|
168
|
-
# criteria.execute_or_raise(id)
|
169
|
-
#
|
170
|
-
# @param [ Object ] args The arguments passed.
|
171
|
-
#
|
172
|
-
# @raise [ Errors::DocumentNotFound ] If nothing returned.
|
173
|
-
#
|
174
|
-
# @return [ Document, Array<Document> ] The document(s).
|
175
|
-
#
|
176
|
-
# @since 2.0.0
|
177
|
-
def execute_or_raise(ids, multi)
|
178
|
-
result = multiple_from_map_or_db(ids)
|
179
|
-
check_for_missing_documents!(result, ids)
|
180
|
-
multi ? result : result.first
|
181
|
-
end
|
182
|
-
|
183
117
|
# Extract a single id from the provided criteria. Could be in an $and
|
184
118
|
# query or a straight _id query.
|
185
119
|
#
|
@@ -226,72 +160,6 @@ module Mongoid
|
|
226
160
|
end
|
227
161
|
end
|
228
162
|
|
229
|
-
# Find the matchind document(s) in the criteria for the provided ids.
|
230
|
-
#
|
231
|
-
# @example Find by an id.
|
232
|
-
# criteria.find(Moped::BSON::ObjectId.new)
|
233
|
-
#
|
234
|
-
# @example Find by multiple ids.
|
235
|
-
# criteria.find([ Moped::BSON::ObjectId.new, Moped::BSON::ObjectId.new ])
|
236
|
-
#
|
237
|
-
# @param [ Array<Moped::BSON::ObjectId> ] args The ids to search for.
|
238
|
-
#
|
239
|
-
# @return [ Array<Document>, Document ] The matching document(s).
|
240
|
-
#
|
241
|
-
# @since 1.0.0
|
242
|
-
def find(*args)
|
243
|
-
ids = args.__find_args__
|
244
|
-
raise_invalid if ids.any?(&:nil?)
|
245
|
-
for_ids(ids).execute_or_raise(ids, args.multi_arged?)
|
246
|
-
end
|
247
|
-
|
248
|
-
# Find the first +Document+ given the conditions, or creates a new document
|
249
|
-
# with the conditions that were supplied.
|
250
|
-
#
|
251
|
-
# @example Find or create the document.
|
252
|
-
# Person.find_or_create_by(:attribute => "value")
|
253
|
-
#
|
254
|
-
# @param [ Hash ] attrs The attributes to check.
|
255
|
-
#
|
256
|
-
# @return [ Document ] A matching or newly created document.
|
257
|
-
def find_or_create_by(attrs = {}, &block)
|
258
|
-
find_or(:create, attrs, &block)
|
259
|
-
end
|
260
|
-
|
261
|
-
# Find the first +Document+ given the conditions, or initializes a new document
|
262
|
-
# with the conditions that were supplied.
|
263
|
-
#
|
264
|
-
# @example Find or initialize the document.
|
265
|
-
# Person.find_or_initialize_by(:attribute => "value")
|
266
|
-
#
|
267
|
-
# @param [ Hash ] attrs The attributes to check.
|
268
|
-
#
|
269
|
-
# @return [ Document ] A matching or newly initialized document.
|
270
|
-
def find_or_initialize_by(attrs = {}, &block)
|
271
|
-
find_or(:new, attrs, &block)
|
272
|
-
end
|
273
|
-
|
274
|
-
# Adds a criterion to the +Criteria+ that specifies an id that must be matched.
|
275
|
-
#
|
276
|
-
# @example Add a single id criteria.
|
277
|
-
# criteria.for_ids([ 1 ])
|
278
|
-
#
|
279
|
-
# @example Add multiple id criteria.
|
280
|
-
# criteria.for_ids([ 1, 2 ])
|
281
|
-
#
|
282
|
-
# @param [ Array ] ids The array of ids.
|
283
|
-
#
|
284
|
-
# @return [ Criteria ] The cloned criteria.
|
285
|
-
def for_ids(ids)
|
286
|
-
ids = mongoize_ids(ids)
|
287
|
-
method = extract_id ? :all_of : :where
|
288
|
-
if ids.size > 1
|
289
|
-
send(method, { _id: { "$in" => ids }})
|
290
|
-
else
|
291
|
-
send(method, { _id: ids.first })
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
163
|
# When freezing a criteria we need to initialize the context first
|
296
164
|
# otherwise the setting of the context on attempted iteration will raise a
|
297
165
|
# runtime error.
|
@@ -306,39 +174,6 @@ module Mongoid
|
|
306
174
|
context and inclusions and super
|
307
175
|
end
|
308
176
|
|
309
|
-
# Get the document from the identity map, and if not found hit the
|
310
|
-
# database.
|
311
|
-
#
|
312
|
-
# @example Get the document from the map or criteria.
|
313
|
-
# criteria.from_map_or_db
|
314
|
-
#
|
315
|
-
# @return [ Document ] The found document.
|
316
|
-
#
|
317
|
-
# @since 2.2.1
|
318
|
-
def from_map_or_db
|
319
|
-
id = extract_id
|
320
|
-
id = klass.fields["_id"].mongoize(id) if id
|
321
|
-
doc = IdentityMap.get(klass, id || selector.except("_type"))
|
322
|
-
return nil if doc == {}
|
323
|
-
doc && doc.matches?(selector) ? doc : first
|
324
|
-
end
|
325
|
-
|
326
|
-
# Get the documents from the identity map, and if not found hit the
|
327
|
-
# database.
|
328
|
-
#
|
329
|
-
# @example Get the documents from the map or criteria.
|
330
|
-
# criteria.multiple_from_map_or_db(ids)
|
331
|
-
#
|
332
|
-
# @param [ ids ] The searched ids.
|
333
|
-
#
|
334
|
-
# @return [ Array<Document> ] The found documents.
|
335
|
-
def multiple_from_map_or_db(ids)
|
336
|
-
return entries if embedded?
|
337
|
-
ids = mongoize_ids(ids)
|
338
|
-
result = from_identity_map(ids)
|
339
|
-
ids.empty? ? result : result + from_database(ids)
|
340
|
-
end
|
341
|
-
|
342
177
|
# Initialize the new criteria.
|
343
178
|
#
|
344
179
|
# @example Init the new criteria.
|
@@ -468,7 +303,7 @@ module Mongoid
|
|
468
303
|
#
|
469
304
|
# @since 1.0.0
|
470
305
|
def only(*args)
|
471
|
-
return clone if args.empty?
|
306
|
+
return clone if args.flatten.empty?
|
472
307
|
args = args.flatten
|
473
308
|
if klass.hereditary?
|
474
309
|
super(*args.push(:_type))
|
@@ -589,6 +424,24 @@ module Mongoid
|
|
589
424
|
crit
|
590
425
|
end
|
591
426
|
|
427
|
+
# Find documents by the provided javascript and scope. Uses a $where but is
|
428
|
+
# different from +Criteria#where+ in that it will pass a code object to the
|
429
|
+
# query instead of a pure string. Safe against Javascript injection
|
430
|
+
# attacks.
|
431
|
+
#
|
432
|
+
# @example Find by javascript.
|
433
|
+
# Band.for_js("this.name = param", param: "Tool")
|
434
|
+
#
|
435
|
+
# @param [ String ] javascript The javascript to execute in the $where.
|
436
|
+
# @param [ Hash ] scope The scope for the code.
|
437
|
+
#
|
438
|
+
# @return [ Criteria ] The criteria.
|
439
|
+
#
|
440
|
+
# @since 3.1.0
|
441
|
+
def for_js(javascript, scope = {})
|
442
|
+
js_query(Moped::BSON::Code.new(javascript, scope))
|
443
|
+
end
|
444
|
+
|
592
445
|
private
|
593
446
|
|
594
447
|
# Are documents in the query missing, and are we configured to raise an
|
@@ -612,45 +465,6 @@ module Mongoid
|
|
612
465
|
end
|
613
466
|
end
|
614
467
|
|
615
|
-
# Create a document given the provided method and attributes from the
|
616
|
-
# existing selector.
|
617
|
-
#
|
618
|
-
# @api private
|
619
|
-
#
|
620
|
-
# @example Create a new document.
|
621
|
-
# criteria.create_document(:new, {})
|
622
|
-
#
|
623
|
-
# @param [ Symbol ] method Either :new or :create.
|
624
|
-
# @param [ Hash ] attrs Additional attributes to use.
|
625
|
-
#
|
626
|
-
# @return [ Document ] The new or saved document.
|
627
|
-
#
|
628
|
-
# @since 3.0.0
|
629
|
-
def create_document(method, attrs = {}, &block)
|
630
|
-
klass.__send__(method,
|
631
|
-
selector.reduce(attrs) do |hash, (key, value)|
|
632
|
-
unless key.to_s =~ /\$/ || value.is_a?(Hash)
|
633
|
-
hash[key] = value
|
634
|
-
end
|
635
|
-
hash
|
636
|
-
end, &block)
|
637
|
-
end
|
638
|
-
|
639
|
-
# Find the first object or create/initialize it.
|
640
|
-
#
|
641
|
-
# @api private
|
642
|
-
#
|
643
|
-
# @example Find or perform an action.
|
644
|
-
# Person.find_or(:create, :name => "Dev")
|
645
|
-
#
|
646
|
-
# @param [ Symbol ] method The method to invoke.
|
647
|
-
# @param [ Hash ] attrs The attributes to query or set.
|
648
|
-
#
|
649
|
-
# @return [ Document ] The first or new document.
|
650
|
-
def find_or(method, attrs = {}, &block)
|
651
|
-
where(attrs).first || send(method, attrs, &block)
|
652
|
-
end
|
653
|
-
|
654
468
|
# Clone or dup the current +Criteria+. This will return a new criteria with
|
655
469
|
# the selector, options, klass, embedded options, etc intact.
|
656
470
|
#
|
@@ -675,44 +489,6 @@ module Mongoid
|
|
675
489
|
super
|
676
490
|
end
|
677
491
|
|
678
|
-
# Get documents from the database only.
|
679
|
-
#
|
680
|
-
# @api private
|
681
|
-
#
|
682
|
-
# @example Get documents from the database.
|
683
|
-
# criteria.from_database(ids)
|
684
|
-
#
|
685
|
-
# @param [ Array<Object> ] ids The ids to fetch with.
|
686
|
-
#
|
687
|
-
# @return [ Array<Document> ] The matching documents.
|
688
|
-
#
|
689
|
-
# @since 3.0.0
|
690
|
-
def from_database(ids)
|
691
|
-
(ids.size > 1 ? any_in(id: ids) : where(id: ids.first)).entries
|
692
|
-
end
|
693
|
-
|
694
|
-
# Get documents from the identity map only.
|
695
|
-
#
|
696
|
-
# @api private
|
697
|
-
#
|
698
|
-
# @example Get documents from the identity map.
|
699
|
-
# criteria.from_identity_map(ids)
|
700
|
-
#
|
701
|
-
# @param [ Array<Object> ] ids The ids to fetch with.
|
702
|
-
#
|
703
|
-
# @return [ Array<Document> ] The matching documents.
|
704
|
-
#
|
705
|
-
# @since 3.0.0
|
706
|
-
def from_identity_map(ids)
|
707
|
-
result = []
|
708
|
-
selection = selector_with_type_selection
|
709
|
-
ids.reject! do |id|
|
710
|
-
doc = IdentityMap.get(klass, id)
|
711
|
-
doc && doc.matches?(selection) ? result.push(doc) : false
|
712
|
-
end
|
713
|
-
result
|
714
|
-
end
|
715
|
-
|
716
492
|
# Used for chaining +Criteria+ scopes together in the for of class methods
|
717
493
|
# on the +Document+ the criteria is for.
|
718
494
|
#
|
@@ -748,34 +524,6 @@ module Mongoid
|
|
748
524
|
selector.merge!(type_selection) if type_selectable?
|
749
525
|
end
|
750
526
|
|
751
|
-
# Convert all the ids to their proper types.
|
752
|
-
#
|
753
|
-
# @api private
|
754
|
-
#
|
755
|
-
# @example Convert the ids.
|
756
|
-
# criteria.mongoize_ids(ids)
|
757
|
-
#
|
758
|
-
# @param [ Array<Object> ] ids The ids to convert.
|
759
|
-
#
|
760
|
-
# @return [ Array<Object> ] The converted ids.
|
761
|
-
#
|
762
|
-
# @since 3.0.0
|
763
|
-
def mongoize_ids(ids)
|
764
|
-
ids.map{ |id| klass.fields["_id"].mongoize(id) }
|
765
|
-
end
|
766
|
-
|
767
|
-
# Convenience method of raising an invalid options error.
|
768
|
-
#
|
769
|
-
# @example Raise the error.
|
770
|
-
# criteria.raise_invalid
|
771
|
-
#
|
772
|
-
# @raise [ Errors::InvalidOptions ] The error.
|
773
|
-
#
|
774
|
-
# @since 2.0.0
|
775
|
-
def raise_invalid
|
776
|
-
raise Errors::InvalidFind.new
|
777
|
-
end
|
778
|
-
|
779
527
|
# Is the criteria type selectable?
|
780
528
|
#
|
781
529
|
# @api private
|