Sort by array field, Realm Flex sync offline

Hello,
I have an Electron app with a Realm database using flexible sync.
I have this schema:

const EntrySchema = {
  name: "Entry",
  properties: {
    _id: { type: "objectId", indexed: true },
    cells: "Entry_cells[]",
  },
  primaryKey: "_id",
};

const Entry_cellsSchema = {
  name: "Entry_cells",
  embedded: true,
  properties: {
    _schema: { type: "int", optional: true, default: 0 },
    body: { type: "string", optional: true, default: "" },
    columnId: { type: "string", optional: true, default: "" },
  },
};

I would like to be able to sort entries by cells.body. I know this is possible with an aggregation.
But I’m offline so I can’t use aggregate.

I would like to do something like the following but I’m afraid it is not supported:

.objects("entries")
.filtered("cells.columnId == $0", columnId)
.sorted([["cells.body", true]["_id", true]]);

Does anyone know if it can be achieved? Thanks.

Unfortunately, sorting by a property of an embedded object is not currently supported in Realm. As you mentioned, one way to achieve this would be to use aggregation, but since you are offline, this is not possible.

One possible workaround is to denormalize your data by adding a new property to the Entry object that stores the value of cells.body. You can update this property whenever a new Entry_cells object is added or modified.

With this approach, you can then sort by the new property using the .sorted() method. Here is an example:

const EntrySchema = {
  name: "Entry",
  properties: {
    _id: { type: "objectId", indexed: true },
    cells: "Entry_cells[]",
    cellsBody: { type: "string", indexed: true }
  },
  primaryKey: "_id",
};

const Entry_cellsSchema = {
  name: "Entry_cells",
  embedded: true,
  properties: {
    _schema: { type: "int", optional: true, default: 0 },
    body: { type: "string", optional: true, default: "" },
    columnId: { type: "string", optional: true, default: "" },
  },
};

// Whenever a new Entry or Entry_cells object is added or modified, update cellsBody
realm.write(() => {
  const entries = realm.objects("Entry");
  for (const entry of entries) {
    let cellsBody = "";
    for (const cell of entry.cells) {
      cellsBody += cell.body;
    }
    entry.cellsBody = cellsBody;
  }
});

// Query and sort by cellsBody
const entries = realm.objects("Entry")
  .filtered("cells.columnId == $0", columnId)
  .sorted("cellsBody", true);

This approach does have the disadvantage of increased storage space and potential inconsistency if cells.body and cellsBody are not kept in sync. However, it may be a feasible workaround for your use case.

1 Like