Class: Parse::Constraint::ArrayNotSetEqualsConstraint

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

Overview

Note:

This constraint uses aggregation pipeline with MongoDB $not and $setEquals.

Not-set-equals constraint using MongoDB aggregation with $not and $setEquals. Matches arrays that do NOT contain exactly the same elements (regardless of order). This is order-independent: [A, B, C] does NOT match [A, B] but [C, B, A] DOES match.

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

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.



1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
# File 'lib/parse/query/constraints.rb', line 1113

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, use $not with $setEquals on mapped objectIds.
    # $ifNull coerces a missing/null field to [] so $map doesn't raise a type
    # error on legacy documents that lack the field. A missing field is
    # treated the same as [] for set-equality purposes.
    pipeline = [
      {
        "$match" => {
          "$expr" => {
            "$not" => {
              "$setEquals" => [
                { "$map" => {
                    "input" => { "$ifNull" => ["$#{field_name}", []] },
                    "as" => "p",
                    "in" => "$$p.objectId",
                  } },
                target_ids,
              ],
            },
          },
        },
      },
    ]
  else
    # For simple value arrays, use $not with $setEquals.
    # $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" => {
            "$not" => {
              "$setEquals" => [
                { "$ifNull" => ["$#{field_name}", []] },
                val,
              ],
            },
          },
        },
      },
    ]
  end

  { "__aggregation_pipeline" => pipeline }
end

#not_set_equalsArrayNotSetEqualsConstraint

A registered method on a symbol to create the constraint.

Examples:

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

Returns:



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

register :not_set_equals