Include Revisions



Overview

Why include revisions:


  • Including revisions may be useful, for example, when an auditing application loads or queries for a document.
    The document's past revisions can be included with the document to make the document's history available for instant inspection.

  • Once loaded to the session, there are no additional trips to the server when accessing the revisions.
    Getting a revision that was included with the document will retrieve it directly from the session.
    This also holds true when attempting to include revisions but none are found.

Including by Creation Time:


  • You can include a single revision by specifying its creation time, see examples below.

  • You can pass local time or UTC, either way the server will convert it to UTC.

  • If the provided time matches the creation time of a document revision, this revision will be included.

  • If no exact match is found, then the first revision that precedes the specified time will be returned.

Including by Change Vector:


  • Each time a document is modified, its Change Vector is updated.

  • When a revision is created,
    the revision's change vector is the change vector of the document at the time of the revision's creation.

  • To include single or multiple document revisions by their change vectors:

    • When modifying the document, store its updated change vector in a property in the document.
      Can be done by patching the document from the Client API or from the Studio.

    • Specify the path to this property when including the revisions, see examples below.

    • e.g.:
      Each time an employee's contract document is modified (e.g. when their salary is raised),
      you can add the current change vector of the document to a dedicated property in the document.
      Whenever the time comes to re-evaluate an employee's terms and their contract is loaded,
      its past revisions can be easily included with it by their change vectors.

Include revisions when Loading document

Include a revision by Time

// The revision creation time
// For example - looking for a revision from last month
const creationTime = new Date();
creationTime.setMonth(creationTime.getMonth() - 1).toLocaleString();

// Load a document:
const order = await session.load("orders/1-A", {
    // Pass the revision creation time to 'includeRevisions'
    // The revision will be 'loaded' to the session along with the document
    includes: builder => builder.includeRevisions(creationTime)
});

// Get the revision by creation time - it will be retrieved from the SESSION
// No additional trip to the server is made
const revision = await session
    .advanced.revisions.get("orders/1-A", creationTime);

Include revisions by Change Vector

// Load a document:
const contract = await session.load("contracts/1-A", {
    includes: builder => builder
        // Pass the path to the document property that contains the revision change vector(s)
        // The revision(s) will be 'loaded' to the session along with the document
        .includeRevisions("revisionChangeVector")  // Include a single revision
        .includeRevisions("revisionChangeVectors") // Include multiple revisions
});

// Get the revision(s) by change vectors - it will be retrieved from the SESSION
// No additional trip to the server is made
const revision = await session
    .advanced.revisions.get(contract.revisionChangeVector);
const revisions = await session
    .advanced.revisions.get(contract.revisionChangeVectors);

// Sample Contract document
class Contract {
    id: string;
    name: string;
    revisionChangeVector: string;
    revisionChangeVectors: string[];
}

Include revisions when making a Query

Include revisions by Time

// The revision creation time
// For example - looking for a revision from last month
const creationTime = new Date();
creationTime.setMonth(creationTime.getMonth() - 1).toLocaleString();

// Define the query:
const query = session.query({collection: "Orders"})
    .whereEquals("ShipTo.Country", "Canada")
    // Pass the revision creation time to 'includeRevisions'
    .include(builder => builder.includeRevisions(creationTime));

// Execute the query:
// For each document in the query results,
// the matching revision will be 'loaded' to the session along with the document
const orderDocuments = await query.all();

// Get a revision by its creation time for a document from the query results
// It will be retrieved from the SESSION - no additional trip to the server is made
const revision = await session
    .advanced.revisions.get(orderDocuments[0].id, creationTime);

Include revisions by Change Vector

// Define the query:
const query = session.query({collection: "Contracts"})
    // Pass the path to the document property that contains the revision change vector(s)
    .include(builder => {
        builder
            .includeRevisions("revisionChangeVector")  // Include a single revision
            .includeRevisions("revisionChangeVectors") // Include multiple revisions
    });

// Execute the query:
// For each document in the query results,
// the matching revisions will be 'loaded' to the session along with the document
const orderDocuments = await query.all();

// Get the revision(s) by change vectors - it will be retrieved from the SESSION
// No additional trip to the server is made
const revision = await session
    .advanced.revisions.get(orderDocuments[0].revisionChangeVector);
const revisions = await session
    .advanced.revisions.get(orderDocuments[0].revisionChangeVectors);
  • See the Contract class definition above.

Include revisions when making a Raw Query

  • Use include revisions in your RQL when making a raw query.

  • Pass either the revision creation time or the path to the document property containing the change vector(s),
    RavenDB will figure out the parameter type passed and include the revisions accordingly.

  • Aliases (e.g. from Users as U) are Not supported by raw queries that include revisions.


Include revisions by Time

// The revision creation time
// For example - looking for a revision from last month
const creationTime = new Date();
creationTime.setMonth(creationTime.getMonth() - 1).toLocaleString();

// Define the Raw Query:
const rawQuery = session.advanced
    // Use 'include revisions' in the RQL
    .rawQuery("from Orders include revisions($p0)")
    // Pass the revision creation time 
    .addParameter("p0", creationTime);

// Execute the query:
// For each document in the query results,
// the matching revision will be 'loaded' to the session along with the document
const orderDocuments = await rawQuery.all();

// Get a revision by its creation time for a document from the query results
// It will be retrieved from the SESSION - no additional trip to the server is made
const revision = await session
    .advanced.revisions.get(orderDocuments[0].Id, creationTime);

Include revisions by Change Vector

// Define the Raw Query:
const rawQuery = session.advanced
    // Use 'include revisions' in the RQL
    .rawQuery("from Contracts include revisions($p0, $p1)")
    // Pass the path to the document properties containing the change vectors
    .addParameter("p0", "revisionChangeVector")
    .addParameter("p1", "revisionChangeVectors");

// Execute the raw query:
// For each document in the query results,
// the matching revisions will be 'loaded' to the session along with the document
const orderDocuments = await rawQuery.all();

// Get the revision(s) by change vectors - it will be retrieved from the SESSION
// No additional trip to the server is made
const revision = await session
    .advanced.revisions.get(orderDocuments[0].revisionChangeVector);
const revisions = await session
    .advanced.revisions.get(orderDocuments[0].revisionChangeVectors);
  • See the Contract class definition above.

Syntax

object includeRevisions(before);
object includeRevisions(path);
Parameters Type Description
before string
  • Creation time of the revision to be included.
  • Pass local time or UTC.
    The server will convert the param to UTC.
  • If no revision was created at this time then the first revision that precedes it is returned.
path string
  • The path to the document property that contains
    a single change vector or an array of change vectors
    of the revisions to be included.
Return value
object
  • When loading a document:
    A builder object that is used to build the include part in the Load request.
  • When querying for a document:
    A builder object that is used to build the include part in the Query RQL expression.
  • Can be used in chaining.

Patching the revision change vector

  • To include revisions when making a query or a raw query,
    you need to specify the path to the document property that contains the revision change vector(s).

  • The below example shows how to get and patch a revision change vector to a document property.

// Get the revisions' metadata for document 'contracts/1-A'
const contractRevisionsMetadata = await session
    .advanced.revisions.getMetadataFor("contracts/1-A");

// Get a change vector from the metadata
const metadata = orderRevisionsMetadata[0];
const changeVector = metadata[CONSTANTS.Documents.Metadata.CHANGE_VECTOR];

// Patch the document - add the revision change vector to a specific document property
await session.advanced.patch("contracts/1-A", "revisionChangeVector", changeVector);

// Save your changes
await session.saveChanges();
  • See the Contract class definition above.