Delete by Query Operation


  • Use DeleteByQueryOperation to delete a large number of documents that match the provided query in a single server call.

  • Dynamic behavior:
    The deletion of documents matching the specified query is performed in batches of size 1024.
    During the deletion process, documents that are added/modified after the delete operation has started
    may also be deleted if they match the query criteria.

  • Background operation:
    This operation is performed in the background on the server.

  • In this page:

Delete by dynamic query

Delete all documents in a collection:

// Define the delete by query operation, pass an RQL querying a collection
$deleteByQueryOp = new DeleteByQueryOperation("from 'Orders'");

// Execute the operation by passing it to Operations.Send
$operation = $store->operations()->send($deleteByQueryOp);

// All documents in collection 'Orders' will be deleted from the server.
from "Orders"

Delete with filtering:

// Define the delete by query operation, pass an RQL querying a collection
$deleteByQueryOp = new DeleteByQueryOperation("from 'Orders' where Freight > 30");

// Execute the operation by passing it to Operations.Send
$operation = $store->operations()->send($deleteByQueryOp);

// * All documents matching the specified RQL will be deleted from the server.

// * Since the dynamic query was made with a filtering condition,
//   an auto-index is generated (if no other matching auto-index already exists).
from "Orders" where Freight > 30

Delete by index query

  • DeleteByQueryOperation can only be performed on a Map-index.
    An exception is thrown when executing the operation on a Map-Reduce index.

  • A few overloads are available, see the following examples:


A sample Map-index:

// The index definition:
// =====================

class IndexEntry
{
    public float $price;

    public function getPrice(): float
    {
        return $this->price;
    }

    public function setPrice(float $price): void
    {
        $this->price = $price;
    }
}

class Products_ByPrice extends AbstractIndexCreationTask
{
    public function __construct()
    {
        parent::__construct();

        $this->map = "from product in products select new {price = product.PricePerUnit}";
    }
}

Delete documents via an index query:

// Define the delete by query operation, pass an RQL querying the index
$deleteByQueryOp = new DeleteByQueryOperation("from index 'Products/ByPrice' where Price > 10");

// Execute the operation by passing it to Operations.Send
$operation = $store->operations()->send($deleteByQueryOp);


// All documents with document-field PricePerUnit > 10 will be deleted from the server.
// Define the delete by query operation
$deleteByQueryOp = new DeleteByQueryOperation(
    // Provide an RQL querying the index
    new IndexQuery("from index 'Products/ByPrice' where Price > 10")
);

// Execute the operation by passing it to Operations.Send
$operation = $store->operations()->send($deleteByQueryOp);

// All documents with document-field PricePerUnit > 10 will be deleted from the server.
from index "Products/ByPrice" where Price > 10

Delete with options:

// OPTIONS: Specify the options for the operation
// (See all other available options in the Syntax section below)
$options = new QueryOperationOptions();
// Allow the operation to operate even if index is stale
$options->setAllowStale(true);
// Get info in the operation result about documents that were deleted
$options->setRetrieveDetails(true);

// Define the delete by query operation
$deleteByQueryOp = new DeleteByQueryOperation(
    new IndexQuery("from index 'Products/ByPrice' where Price > 10"), // QUERY: Specify the query
    $options // OPTIONS:
);

// Execute the operation by passing it to Operations.Send
/** @var Operation $operation */
$operation = $store->operations()->sendAsync($deleteByQueryOp);

// Wait for operation to complete
/** @var BulkOperationResult $result */
$result = $operation->waitForCompletion(Duration::ofSeconds(15));

// * All documents with document-field PricePerUnit > 10 will be deleted from the server.

// * Details about deleted documents are available:
$details =  $result->getDetails();
$documentIdThatWasDeleted = $details[0]->getId();
from index "Products/ByPrice" where Price > 10

Syntax

class DeleteByQueryOperation implements OperationInterface
{
    /**
     * Usage:
     *   - new DeleteByQueryOperation("from 'Orders'")
     *   - new DeleteByQueryOperation("from 'Orders'", $options)
     *
     *   - new DeleteByQueryOperation(new IndexQuery("from 'Orders'"))
     *   - new DeleteByQueryOperation(new IndexQuery("from 'Orders'"), $options)
     *
     * @param IndexQuery|string|null $queryToDelete
     * @param QueryOperationOptions|null $options
     */
    public function __construct(IndexQuery|string|null $queryToDelete, ?QueryOperationOptions $options = null) {
        // ...
    }

    // ...
}

Parameter Type Description
$queryToDelete string The RQL query to perform
$queryToDelete IndexQuery Holds all the information required to query an index
$options ?QueryOperationOptions Object holding different setting options for the operation

class QueryOperationOptions
{
    // Indicates whether operations are allowed on stale indexes.
    private bool $allowStale = false;

    // Limits the number of base operations per second allowed.
    // DEFAULT: no limit
    private ?int $maxOpsPerSecond = null;

    // If AllowStale is set to false and index is stale,
    // then this is the maximum timeout to wait for index to become non-stale.
    // If timeout is exceeded then exception is thrown.
    // DEFAULT: null (if index is stale then exception is thrown immediately)
    private ?Duration $staleTimeout = null;

    // Determines whether operation details about each document should be returned by server.
    private bool $retrieveDetails = false;

    // Ignore the maximum number of statements a script can execute.
    // Note: this is only relevant for the patchByQueryOperation.
    private bool $ignoreMaxStepsForScript = false;

    // getters and setters
}