module Mongoid::Matcher
Utility module containing methods which assist in performing in-memory matching of documents with MQL query expressions.
@api private
Public Instance Methods
Extracts field values in the document at the specified key.
The document can be a Hash or a model instance.
The key is a valid MongoDB dot notation key. The following use cases are supported:
-
Simple field traversal (‘foo`) - retrieves the field `foo` in the current document.
-
Hash/embedded document field traversal (‘foo.bar`) - retrieves the field `foo` in the current document, then retrieves the field `bar` from the value of `foo`. Each path segment could descend into an embedded document or a hash field.
-
Array element retrieval (‘foo.N`) - retrieves the Nth array element from the field `foo` which must be an array. N must be a non-negative integer.
-
Array traversal (‘foo.bar`) - if `foo` is an array field, and the elements of `foo` are hashes or embedded documents, this returns an array of values of the `bar` field in each of the hashes in the `foo` array.
This method can return an individual field value in some document or an array of values from multiple documents. The array can be returned because a field value in the specified path is an array of primitive values (e.g. integers) or because a field value in the specified path is an array of documents (e.g. a one-to-many embedded association), in which case the leaf value may be a scalar for each individual document. If the leaf value is an array and a one-to-many association was traversed, the return value will be an array of arrays. Note that an individual field value can also be an array and this case is indistinguishable from and behaves identically to association traversal for the purposes of, for example, subsequent array element retrieval.
@param [ Document
| Hash | String ] document The document to extract from. @param [ String ] key The key path to extract.
@return [ Object
| Array ] Field value or values.
# File lib/mongoid/matcher.rb, line 46 def extract_attribute(document, key) # The matcher system will wind up sending atomic values to this as well, # when attepting to match more complex types. If anything other than a # Document or a Hash is given, we'll short-circuit the logic and just # return an empty array. return [] unless document.is_a?(Hash) || document.is_a?(Document) # Performance optimization; if the key does not include a '.' character, # it must reference an immediate attribute of the document. unless key.include?('.') hash = document.respond_to?(:attributes) ? document.attributes : document key = find_exact_key(hash, key) return key ? [ hash[key] ] : [] end if document.respond_to?(:as_attributes, true) # If a document has hash fields, as_attributes would keep those fields # as Hash instances which do not offer indifferent access. # Convert to BSON::Document to get indifferent access on hash fields. document = document.send(:as_attributes) end current = [document] key.to_s.split('.').each do |field| new = [] current.each do |doc| case doc when Hash actual_key = find_exact_key(doc, field) if !actual_key.nil? new << doc[actual_key] end when Array if (index = field.to_i).to_s == field if doc.length > index new << doc[index] end end doc.each do |subdoc| if Hash === subdoc actual_key = find_exact_key(subdoc, field) if !actual_key.nil? new << subdoc[actual_key] end end end end end current = new break if current.empty? end current end
Indifferent string or symbol key lookup, returning the exact key.
@param [ Hash ] hash The input hash. @param [ String | Symbol ] key The key to perform indifferent lookups with.
@return [ String | Symbol | nil ] The exact key (with the correct type) that exists in the hash, or nil if the key does not exist.
# File lib/mongoid/matcher.rb, line 108 def find_exact_key(hash, key) key_s = key.to_s return key_s if hash.key?(key_s) key_sym = key.to_sym hash.key?(key_sym) ? key_sym : nil end