Couchbase’s Global Secondary Indexes (GSIs) and MapReduce Views are both indexing mechanisms, but they solve fundamentally different problems in how you access your data.

Let’s see GSIs in action. Imagine you have a bucket named travel-sample with documents like this:

{
  "callsign": "BA2877",
  "flight": "BA2877",
  "destination": {
    "city": "London",
    "country": "United Kingdom"
  },
  "airline": "British Airways",
  "utc": "2017-07-20T10:00:00.000Z",
  "id": 14,
  "type": "flight"
}

If you want to find all flights to "London" efficiently, a GSI is your tool. You’d create it like this:

couchbase-cli gsi-manage -c <host>:<port> -u <username> -p <password> --create --index-name idx_destination_city --bucket travel-sample --fields '["destination.city"]'

Now, querying becomes a breeze:

SELECT * FROM `travel-sample` WHERE `destination.city` = "London";

This query will use idx_destination_city to quickly locate the relevant documents.

Views, on the other hand, are designed for more complex, multi-document transformations and aggregations. They are built on a MapReduce paradigm. A view has two parts: a map function and an optional reduce function. The map function processes each document individually, emitting keys and values. The reduce function then aggregates these emitted keys and values across multiple documents.

Consider a scenario where you need to count the number of flights per airline. This is a perfect use case for a view.

First, you’d define the view in your design document:

{
  "views": {
    "flights_by_airline": {
      "map": "function (doc, meta) { if (doc.type == 'flight') { emit(doc.airline, 1); } }",
      "reduce": "function (key, values, rereduce) { return sum(values); }"
    }
  }
}

The map function iterates through documents. If a document has type: "flight", it emits the airline as the key and 1 as the value. The reduce function then sums up all the 1s for each airline.

To query this view:

curl "http://<host>:8092/travel-sample/_design/dev_flights/_view/flights_by_airline?group=true"

The group=true parameter tells Couchbase to apply the reduce function to group the results by the emitted keys (airlines). The output might look like this:

{
  "rows": [
    { "key": "Air France", "value": 120 },
    { "key": "British Airways", "value": 150 },
    { "key": "KLM", "value": 90 }
    // ... more airlines
  ]
}

The core difference lies in their purpose. GSIs are primarily for point lookups and range scans on specific fields, enabling SQL-like queries. They are built and maintained automatically by Couchbase as you define them. Views, conversely, are for ad-hoc aggregations, transformations, and complex filtering across potentially many documents, requiring you to define the map and reduce logic yourself. They are typically built on demand.

A common misconception is that views are simply "older" or "less performant" than GSIs. While GSIs are generally faster for direct field lookups, views offer a power that GSIs don’t: the ability to perform complex aggregations and transformations directly within the database, reducing the need for client-side processing. You can even combine multiple emit statements in a single map function to index the same document for different query patterns, a flexibility not directly available with GSIs.

When you query a GSI, Couchbase directly uses the index structure to find matching documents. For views, Couchbase first executes the map function over the relevant documents (or a subset if you provide query parameters like startkey or endkey) and then, if a reduce function is present and requested, it aggregates the emitted results. This makes GSIs ideal for filtering and sorting in WHERE clauses, while views excel at producing summarized reports or derived data sets.

The next step after mastering these indexing strategies is understanding how to optimize them for performance, especially when dealing with high-volume data or complex query patterns.

Want structured learning?

Take the full Couchbase course →