Class: Parse::Constraint::ArraySetEqualsConstraint

Inherits:
Parse::Constraint show all
Defined in:
lib/parse/query/constraints.rb

Overview

Note:

This constraint uses aggregation pipeline with MongoDB $setEquals.

Set equality constraint using MongoDB aggregation with $setEquals. Matches arrays that contain exactly the same elements, regardless of order. This is order-independent matching: [A, B] matches [B, A] but not [A, B, C].

q.where :field.set_equals => ["rock", "pop"]
q.where :tags.set_equals => [category1, category2]  # for pointers

For pointer arrays (has_many relations), pass Parse objects or pointers. The constraint will automatically extract objectIds for comparison.

Instance Attribute Summary

Attributes inherited from Parse::Constraint

#operand, #operation, #operator, #value

Instance Method Summary collapse

Methods inherited from Parse::Constraint

#as_json, constraint_keyword, create, formatted_value, #formatted_value, #initialize, #key, #precedence, register, #to_s

Constructor Details

This class inherits a constructor from Parse::Constraint

Instance Method Details

#buildHash

Returns the compiled constraint using aggregation pipeline.

Returns:

  • (Hash)

    the compiled constraint using aggregation pipeline.



837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
# File 'lib/parse/query/constraints.rb', line 837

def build
  val = formatted_value
  val = [val].compact unless val.is_a?(Array)

  field_name = Parse::Query.format_field(@operation.operand)

  # Check if values are pointers (Parse objects or pointer objects)
  is_pointer_array = val.any? do |item|
    item.respond_to?(:pointer) || item.is_a?(Parse::Pointer)
  end

  if is_pointer_array
    # Extract objectIds from pointers for comparison
    target_ids = val.map do |item|
      if item.respond_to?(:id)
        item.id
      elsif item.is_a?(Parse::Pointer)
        item.id
      else
        item
      end
    end

    # Validate all IDs are present (unsaved objects have nil IDs)
    if target_ids.any?(&:nil?)
      raise ArgumentError, "#{self.class.name}: Cannot use unsaved objects (missing ID) in array constraint"
    end

    # For pointer arrays, we need to map the objectIds from the stored pointers.
    # $ifNull coerces a missing/null field to [] so $map (and $setEquals) don't
    # raise type errors on legacy documents that lack the field.
    pipeline = [
      {
        "$match" => {
          "$expr" => {
            "$setEquals" => [
              { "$map" => {
                  "input" => { "$ifNull" => ["$#{field_name}", []] },
                  "as" => "p",
                  "in" => "$$p.objectId",
                } },
              target_ids,
            ],
          },
        },
      },
    ]
  else
    # For simple value arrays (strings, numbers, etc.).
    # $ifNull coerces a missing/null field to [] so $setEquals doesn't raise
    # a type error on legacy documents that lack the field.
    pipeline = [
      {
        "$match" => {
          "$expr" => {
            "$setEquals" => [
              { "$ifNull" => ["$#{field_name}", []] },
              val,
            ],
          },
        },
      },
    ]
  end

  { "__aggregation_pipeline" => pipeline }
end

#set_equalsArraySetEqualsConstraint

A registered method on a symbol to create the constraint.

Examples:

q.where :field.set_equals => ["value1", "value2"]
q.where :categories.set_equals => [cat1, cat2]

Returns:



834
# File 'lib/parse/query/constraints.rb', line 834

register :set_equals