Cloudant connector hit its 2.x major release with several improvements. The most significant change is the support of LoopBack model indexes to optimize query performance.

In loopback-connector-cloudant@1.x, all properties are treated indexable. It could cause a slow response time when called with larger data set. In version 2.x we allow users to specify indexable properties and multiple properties in a composed index. The connector then creates proper indexes based on the model definition.

The indexes are created when you migrate or update your model by calling automigrate or autoupdate. The function autoupdate only compares your new indexes with the ones existing in database, and updates the changed ones. However automigrate cleans up the existing model instances first, then executes autoupdate to update the indexes. Therefore be careful when you call automigrate. See details in documentation automigrate vs autoupdate

Define Your Index

Before deciding which properties are indexable and indexes to create, you need to know the queries on your model which are frequently made and have a basic understanding of the index system in Cloudant database. The connector doesn’t inject an index in a query if you don’t specify it. And the Cloudant database has an algorithm that automatically fetches the proper index when a query doesn’t have one.

Here is how it chooses the index:

_find chooses which index to use for responding to a query, unless you specify an index at query time. If there are two or more json type indexes on the same fields, the index with the smallest number of fields in the index is preferred. If there are still two or more candidate indexes, the index with the first alphabetical name is chosen.

For example, there are two indexes available in the database:

index1: {
  fields: ['name', 'city']
},
index2: {
  fields: ['name', 'city', 'category']
}

When queried with property name and city using MyModel.find({where: {name: 'foo', city: 'bar'}}), index1 is automatically picked since it’s “the index with the smallest number of fields”.

You can define your model indexes in two ways:

  • Mark a single property as indexable
  • Create composed index with multiple fields

Index for a Single Property

You can set index: true in a property’s configuration to mark it as indexable. And the created index only contains one field.

For example in a model Pet, mark the property category as indexable:

// in file /commons/models/Pet.json 
{
  "name": "Pet",
  "base": "PersistedModel",
  "properties": {
    "name": {
      "type": "string"
    },
    "category": {
      "type": "string",
      "index": true
    }
  },
  ...
}

The created index will be used when you do a query with category filter:

Pet.find(
  where: {
    category: 'dog'
  }
})

Composed Index for Multiple Properties

You can define a composed index with multiple fields by adding an entry in a model definition’s indexes property. The syntax of a index definition is

index_name: {
  keys: {
    field1: direction,
    field2: direction,
    ...
  }
}

You can find the details of the syntax in loopback indexes

Here is an example of defining an index containing fields name and category in model Pet:

// in file /commons/models/Pet.json 
{
  "name": "Pet",
  "base": "PersistedModel",
  "properties": {
    "name": {
      "type": "string"
    },
    "category": {
      "type": "string"
    }
  },
  "indexes": {
    "pet_name_and_category": {
      "keys": {
        // The direction code `-1` means DESC and `1` means ASC. 
        "name": -1,
        "category": -1
      },
    },
  },
  ...
}

Please note Cloudant doesn’t allow a mixed direction for multiple fields in one index, given the example above, both properties are in DESC order. If people specify different directions in an index, we coerce them to be the same as the one for first key property.

For example:

"indexes": {
  "pet_name_and_category": {
    "keys": {
      "name": 1,
      "category": -1
    },
  },
},

The created index will be in ASC order since the direction code for property name is 1.

Customize the Model Name Property

When looking at the created index in the database, you may probably notice that every index has an extra field besides the ones you specified in the model.json file. It’s because to organize unstructured data into collections, all the data contains a property that specifies the loopback model name. By default the property is called loopback__model__name, you can customize it in model.json file:

{
  "name": "User",
  "base": "PersistedModel",
  ...
  "cloudant": {
    "modelIndex": "your_customized_lb_model_name",
    "database": "test"
  },
  ...
}

Ad-hoc Query

We suggest users create proper indexes for those properties frequently queried with, while sometimes you may still do ad-hoc queries with properties that are not included in any indexes. In this case, Cloudant automatically uses all_fields index to return the result.

Reference

Call for Action

LoopBack’s future success counts on you. We appreciate your continuous support and engagement to make LoopBack even better and meaningful for your API creation experience. Please join us and help the project by: