Live Query that updates only when the set of matching documents changes?

I’m using the Couchbase Lite Swift SDK syncing with Capella. Suppose I have an SQL++ query like this:

SELECT *, Meta.id() FROM `scopeX.CollectionFoo` WHERE someFooProperty = “blah”

If I turn this into a Live Query, I get new results anytime any property of a matching CollectionFoo document changes.

Instead, I’d like to get new results only when NEW CollectionFoo matching documents are created OR existing matching documents are deleted—basically, I want to know only when the set of returned documents changes. I don’t care about changes to the various properties of matching documents; only when they enter or leave the matching set.

Is there a way for me to structure the query to achieve that?

There isn’t a way for you to query that directly, but if you save the count from the previous results and compare it with the current you should be able to see if the set changed.

If that is too heavyweight you could run a live query on SELECT COUNT(*) instead to get the same information, and then run the full query manually when the count changes.

Note that to show deleted queries you will need to make use of meta().deleted in the WHERE clause.

I thought about count, but I’m not sure that’ll work. If one document is deleted and one document is added, the count remains the same but the set of matching documents has changed. Can I rely on the live query firing once for every single change, or are some rapid-fire changes coalesced into a single liveQuery update?

What if I fetch only the ids of matching documents, like this?

SELECT Meta.id() FROM `scopeX.CollectionFoo` WHERE someFooProperty = “blah”

With this query, changes to any properties of matching documents should not re-fire the query, right? It would only re-fire when the ids of matching documents change?

Some changes are going to be coalesced if the changes are too rapid. Specifically if two or more changes happen within 250 ms of each other they will be coalesced.

You can take the approach of tracking the IDs like you said, but you will need to take a bit more care if you want to get the ID of a deleted document as this query will only report non-deleted. It will only fire if the results of the query change, as you mentioned.

That’s actually perfect for my use-case. I explicitly want any deleted documents to be excluded from the new result set that the liveQuery returns, leaving me only the documents that currently match the WHERE.

Context: I’m essentially building Realm’s “live collection” type on top of Couchbase. It’s a collection of Swift objects that stays in sync with the state of the database. The only downside to the “query ids only” approach is that I have to then issue a second query to get the actual properties of any new document that’s been added to the matched set. I was hoping to avoid that, but it sounds like that’s not possible.

In my experience thus far, Couchbase seems plenty fast enough when querying for an object by its ID, so I should survive.

I’m not sure about this case, but that is (almost) the pattern to get data fastest with the non-lite SDKs. Instead of a second query to get the documents, use concurrent kv calls. The kv calls get the documents directly from their respective nodes, versus query, which pulls the documents first to the query node, and then from the query node to the client.

I’m new to Couchbase, so I may not understand fully. I think I am using the Lite APIs since I’m working with the Swift SDK, which is Couchbase Lite?

I’m not familiar with “kv calls” instead of queries. Can you provide a brief example?

@mreiche is talking about server-side operations; not relevant to Lite. Sorry for any confusion.

2 Likes