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.



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
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
# File 'lib/parse/query/constraints.rb', line 1142

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:



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

register :not_set_equals