Skip to main content

Compare-Exchange in Dynamic Queries


Projecting compare-exchange values in query results

  • You can project values from compare-exchange items alongside fields from the queried documents.

  • The following example is based on the sample data described in: Create sample compare-exchange items.
    In this example, we want to retrieve the current number of guests in each room.
    We query all HotelRoom documents and project:

    • the number of guests (from the compare-exchange item's value), and
    • the room number (from the document field).
  • No auto-index is created in this case, since the query doesn’t apply any filters.

// The session does not need to be opened in cluster-wide mode
using (var session = store.OpenSession())
{
List<ProjectedNumberOfGuests> numberOfGuestsPerRoom = session
.Query<HotelRoom>()
.Select(x => new ProjectedNumberOfGuests
{
// Project content from the compare-exchange item:
// Call 'RavenQuery.CmpXchg' to load the compare-exchange value by its key.
CurrentNumberOfGuests =
RavenQuery.CmpXchg<HotelRoomCurrentDetails>(x.RoomNumber).CurrentNumberOfGuests,

// Project content from the document:
RoomNumber = x.RoomNumber
})
.ToList();
}

Filtering by compare-exchange value

Example 1 - Filtering when the compare-exchange value is a string

  • You can filter documents based on a compare-exchange value.
    For example, to find a user with a blocked email address,
    you can filter by the compare-exchange value that stores the blocked email.

  • Limitation:
    When filtering with RavenQuery.CmpXchg inside the Where predicate (as shown in this example),
    the compare-exchange value must be a string.
    If your compare-exchange value is of another type, you can still filter the results - see the next example.

  • Since this query uses filtering, RavenDB will automatically create an auto-index to serve it.
    In this case, the auto-index Auto/Users/ByEmail will be created.

// First, let's create a compare-exchange item with a blocked email address for this example:
var putResult = store.Operations.Send(new PutCompareExchangeValueOperation<string>(
"blocked-address", "someUser@Company.com", 0));

// Query the 'Users' collection
// Find a user with an email address that matches the blocked address:
// (The session does not need to be opened in cluster-wide mode)
using (var session = store.OpenSession())
{
var blockedUser = session.Query<User>()
// Call 'RavenQuery.CmpXchg' to load the compare-exchange value by its key
// Filter the users collection by the value:
.Where(x => x.Email == RavenQuery.CmpXchg<string>("blocked-address"))
.FirstOrDefault();
}

// The results will include the user document whose email address is "someUser@company.com"
// (assuming such a user exists in your data).

Example 2 - Filtering when the compare-exchange value is an object

  • The following example shows how to filter documents based on a compare-exchange value that is an object.
    We query for users whose email ends with one of the domains stored in the object held by the compare-exchange item.

  • Retrieve the compare-exchange value outside the query, then use its content to build the filter logic.

  • Since this query uses filtering, RavenDB will automatically create an auto-index to serve it.
    In this case, the auto-index Auto/Users/ByEmail will be created.

// First, let's create a compare-exchange item with a value that is an object.
// The object contains multiple blocked email domains for this example.
var putResult = store.Operations.Send(new PutCompareExchangeValueOperation<string>(
"blocked-domains",
new BlockedDomains() { Domains = ["suspicious-company-1.com", "suspicious-company-2.org"]},
0));

// Retrieve the compare-exchange value before running the query
BlockedDomains blockedDomains = store.Operations.Send(
new GetCompareExchangeValueOperation<BlockedDomains>("blocked-domains")).Value;

// Query the 'Users' collection
// Find users whose email address ends with one of the blocked domains.
// (The session does not need to be opened in cluster-wide mode)
using (var session = store.OpenSession())
{
var blockedUsers = session.Query<User>()
.Where(user =>
user.Email.EndsWith(blockedDomains.Domains[0]) ||
user.Email.EndsWith(blockedDomains.Domains[1]))
.ToList();
}

// The results will include users whose email address domain ends with
// one of the values stored in the compare-exchange item,
// assuming such users exist in your data.

Syntax

RavenQuery.CmpXchg()

This method can be used to filter a LINQ query
or to project fields from a compare-exchange value into the query results.

// Get a compare-exchange value by key.
public static T CmpXchg<T>(string key)