Deep queries in Couchbase Lite

Hi,

My documents have a quite deep structure with multilangual options. How would I go about creating a View for this document? Note: I want the “text” properties within the nested “depotProperties → LocalizedNames” to be searchable (queryable).

Here’s a sample of my documents:

{
  "type": "Depot",
  "depotProperties": [
    {
      "depotTypeId": "a762d3a4",
      "localizedNames": [
        {
          "culture": "de-DE",
          "text": "Hersteller"
        },
        {
          "culture": "en-US",
          "text": "Manufacturer"
        }
      ]
    },
    {
      "depotTypeId": "f0ca7b6a",
      "localizedNames": [
        {
          "culture": "de-DE",
          "text": "Information"
        },
        {
          "culture": "en-US",
          "text": "Information"
        }
      ]
    }
  ],
  "localizedNames": [
    {
      "culture": "de-DE",
      "text": "Geschäft"
    {
      "culture": "en-US",
      "text": "Business"
    }
  ]
}

What kinds of queries do you want to run? Can you be more specific?

I have a collection of depots. The depots can be filtered by the user. The fields we want to be queryable/searchable are the various “depotProperties” (manufacturer, etc). I.e. we need to make the nested “text” fields indexed so we can query them. We don’t know how to set up a view for this…

So I’ve tried to do a View like this:

    private void RegisterIndexes()
    {
        _elementRepository.GetView()
            .SetMap((doc, emit) =>
            {
                if (!doc.ContainsKey("type"))
                    return;
  				
                if (!doc["type"].Equals("Depot"))
                    return;

                if (!doc.ContainsKey("localizedNames"))
                    return;

                var localizedNames = doc["localizedNames"] as JArray;
                if (localizedNames == null)
                    return;

                foreach (var localizedName in localizedNames)
                {
                    emit(localizedName["text"], null);
                }

            }, "1.10");
    }

When I do a query on this (for example; setting the Start- and EndKey to “Manufacturer”) I get the correct documents.

However, when I chose to fetch/query all documents of the type “Depot”, I get one object per emitted, i.e. I get duplicates (“Manufacturer” and “Hersteller” returns in two different objects, even though they belong in the same document).

Is it because my View is faulty, or is this the correct behaviour?

That’s a good view for searching for a specific localized string (the "text" property.)

However, when I chose to fetch/query all documents of the type “Depot”, I get one object per emitted

That’s correct. Remember, queries don’t return documents, they return index entries. And you’re emitting multiple entries per document.

If you want a query that returns one row per document, you’ll need a different view.

1 Like

Thank you very much for your valuable answer.

I suppose that if we would try one row per document, then we can’t emit in a for-loop…

Also, one more question on the subject; we want to have one more field indexed. Should we create a new view for that purpose, or can we emit more in the same view? What is the suggested way?

If you want to index a different field, you need a different view, because a view is basically an index.

Does this mean I can’t query a number of different fields in a single search query? I would like to include the nested localizedName text properties in the search as well.

You can include as much data as you want in the value you emit. But a query does a scan of a single index, which has to be sorted by a single criterion, with one key as the primary, and optional secondary, etc. keys (if you use an array.)

1 Like