mongoid 3.0.23 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|