Class: Parse::Constraint::ArraySubsetOfConstraint

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

Overview

Note:

This constraint uses MongoDB aggregation pipeline with $setIsSubset. While $expr expressions cannot utilize field indexes, aggregation enables set operations not available in standard Parse queries.

Subset constraint - array only contains elements from the given set. Uses MongoDB aggregation with $setIsSubset.

# Find items where tags only contain elements from the allowed list
q.where :tags.subset_of => ["rock", "pop", "jazz"]

# This will match:
#   ["rock"] - yes (subset)
#   ["rock", "pop"] - yes (subset)
#   ["rock", "classical"] - no ("classical" not in allowed set)

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.



1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
# File 'lib/parse/query/constraints.rb', line 1280

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
  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
    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

    # $ifNull coerces a missing/null field to [] so $map (and $setIsSubset)
    # don't raise type errors on legacy documents that lack the field.
    # The empty set is a subset of every set, so a missing field matches
    # any subset_of target — consistent with treating missing as [].
    pipeline = [
      {
        "$match" => {
          "$expr" => {
            "$setIsSubset" => [
              { "$map" => {
                  "input" => { "$ifNull" => ["$#{field_name}", []] },
                  "as" => "p",
                  "in" => "$$p.objectId",
                } },
              target_ids,
            ],
          },
        },
      },
    ]
  else
    # $ifNull coerces a missing/null field to [] so $setIsSubset doesn't
    # raise a type error on legacy documents that lack the field.
    pipeline = [
      {
        "$match" => {
          "$expr" => {
            "$setIsSubset" => [
              { "$ifNull" => ["$#{field_name}", []] },
              val,
            ],
          },
        },
      },
    ]
  end

  { "__aggregation_pipeline" => pipeline }
end

#subset_ofArraySubsetOfConstraint

A registered method on a symbol to create the constraint.

Examples:

q.where :tags.subset_of => ["rock", "pop", "jazz"]

Returns:



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

register :subset_of