0

My vehicle logbook app stores the data of the trips. It should also store the changes made to a specific trip; thus, anyone can see if and what data has been changed after the first entry of the trip. Since there are usually not many changes, I thought about storing the whole trip data with each change.

Due to its simple offline first functionality, I want to use AceBase, a NoSQL database. From the web client, I want to directly access the database on the AceBase-Server. I do not want to put an application server in between.

However, I could not find an elegant way to get only the current data of all the trips.

I only found this solution, which requires to load all the changes from the server:

import { AceBaseClient } from "acebase-client";

export type TripChange = {
    changedAt: Date;
    tripId: string;
    purpose: string;
};

/** returns the current trips, i.e. all the trips
  * from the latest tripchanges
  */
export async function currentTrips(
    db: AceBaseClient,
    vehicleId: string
  ):Promise<TripChange[]> {

    // Getting all the trip changes
    // sorted by trip and 
    // then in descending order by the timestamp of the change
    const tripChanges = (
      await db
        .ref(`vehicles/${vehicleId}/tripchanges`)
        .query()
        .sort("tripId")
        .sort("changedAt", false)
        .get<TripChange>()
    ).getValues();

    // take the first (=newest) change of a trip 
    // and push its data to the result array
    const result: TripChange[] = [];
    let lastTripId = "";
    for (const tripChange of tripChanges) {
      if (tripChange.tripId !== lastTripId) {
        result.push(tripChange);
        lastTripId = tripChange.tripId;
      }
    }
    return result;
  }

A test of such a function would look like:

  const trip_changes_ref =
    "vehicles/Scenic220/tripchanges";
  await db.ref(trip_changes_ref).push({
    changedAt: new Date(2023, 3, 1),
    tripId: "idA",
    purpose: "pA1",
  });
  await db.ref(trip_changes_ref).push<TripChange>({
    changedAt: new Date(2023, 3, 2),
    tripId: "idB",
    purpose: "pB1",
  });
  await db.ref(trip_changes_ref).push<TripChange>({
    changedAt: new Date(2023, 3, 3),
    tripId: "idA",
    purpose: "pA2",
  });
  await db.ref(trip_changes_ref).push<TripChange>({
    changedAt: new Date(2023, 2, 1),
    tripId: "idA",
    purpose: "pA0",
  });

  const trips = await currentTrips(db, "Scenic220");
  // console.log({ trips });
  expect(trips).toHaveLength(2);
  expect(trips[0]?.tripId).toBe("idA");
  expect(trips[0]?.purpose).toBe("pA2");
  expect(trips[1]?.tripId).toBe("idB");
  expect(trips[1]?.purpose).toBe("pB1");

In SQL, a query only returning the current data of the trips would be like that:

CREATE TABLE tripchanges (
  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
  changed_at TIMESTAMP DEFAULT NOW(),
  vehicle_id VARCHAR(250),
  trip_id VARCHAR(100),
  purpose VARCHAR

);

WITH m AS (
  SELECT trip_id, MAX(changed_at) AS latest
    FROM tripchanges
    GROUP BY trip_id
)
SELECT * FROM tripchanges,m 
  WHERE tripchanges.trip_id=m.trip_id AND changed_at=m.latest 
    AND tripchanges.vehicle_id='Scenic220';

Is there a similarly smart way in AceBase?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.