Skip to content

Migrations

Ryan Govostes edited this page Jul 17, 2022 · 13 revisions

Sealog does not yet have database migrations, and this has caused some grief when older versions of the database are not compatible.

Here are some notes from migrating from Sealog Alvin 0.9.0 to 1.0.12-rc.

Cruises need a cruise_vessel specified, which is always the R/V Atlantis.

db.cruises.updateMany(
    { $or: [
      { "cruise_additional_meta.cruise_vessel": { $exists: false } },
      { "cruise_additional_meta.cruise_vessel": "" },
    ] },
    { $set: { "cruise_additional_meta.cruise_vessel" : "R/V Atlantis" } }
)

To reset the admin user password, compute the password:

python3 -c 'import bcrypt; print(bcrypt.hashpw(b"asdf", bcrypt.gensalt(10)))' 

and insert it into the database with:

db.users.update({ username: "admin" }, { $set: { password: "<output of above command>" } })

On April 28, 2021 the cruise SKQ201918S had an error in which the cruise_pi key was in the cruise structure rather than under cruise_additional_meta.

db.cruises.update(
    { "cruise_pi": { $exists: true } },
    { $rename: { "cruise_pi" : "cruise_additional_meta.cruise_pi" } }
)

On upgrade to Sealog version 2.1.3 we saw database errors from cruise_additional_meta.cruise_name being empty, perhaps due to this change 91a63c3062746da5f4f100027583e2e706232fc9 probably because cruiseSuccessResponse includes a cruiseAdditionalMetaCreate mapping.

db.cruises.updateMany(
    { $or: [
      { "cruise_additional_meta.cruise_name": { $exists: false } },
      { "cruise_additional_meta.cruise_name": "" },
    ] },
    { $set: { "cruise_additional_meta.cruise_name" : "Untitled Cruise" } }
)

We had a request to show "Local X/Y/Z" instead of "Alvin X/Y/Z" especially with Jason.

for (var d of ["x","y","z"]) {
    db.event_aux_data.updateMany(
        { "data_array.data_name": "alvin_" + d },
        { $set: { "data_array.$.data_name" : "local_" + d } }
    )
}

db.event_aux_data.updateMany(
    { "data_source": "vehicleRealtimeAlvinCoordData" },
    { $set: { "data_source" : "vehicleRealtimeLocalCoordData" } }
)

We needed to clean up duplicate identical vehicleRealtimeAlvinCoordData entries. The following complex query aggregates aux_data entries that have a common event_id and removes all but one, provided they are equal.

db.event_aux_data.aggregate(
    [
        { 
            $match: {
                "data_source": "vehicleRealtimeAlvinCoordData",
            }
        },
        {
            $group: {
                _id: "$event_id",
                ids: { $push: "$_id" },
                contents: { $push: "$data_array" },
                count: { $sum: 1 },
            }
        },
        {
            $match: { 
                count: { $gte: 2 } 
            }
        },
    ],
    { allowDiskUse: true }
).forEach((dupes) => {
    // Check that they are all equal before we even consider deleting anything
    let allSame = dupes.contents.every((v) => JSON.stringify(v) === JSON.stringify(dupes.contents[0]));
    if (!allSame) {
        print("Event " + dupes._id + " has duplicates that don't match!");
        return;
    }

    // Drop the duplicates
    print(`Dropping ${dupes.count-1} duplicates from ${dupes._id}`);
    db.event_aux_data.remove({
        _id : {
            $in: dupes.ids.slice(1),
        }
    });
});

// Merge local_x/y fields back into the vehicleRealtimeNavData auxdata record,
// deleting the old vehicleRealtimeLocalCoordData record.
//
// Also should do the same with vehicleReNavAlvinCoordData -> vehicleReNavData.
db.event_aux_data.aggregate(
    [
        { 
            $match: {
                "data_source": {
                    $in: [
                        "alvinRealtimeNavData",
                        "vehicleRealtimeNavData",
                        "vehicleRealtimeAlvinCoordData",
                        "vehicleRealtimeLocalCoordData",
                    ]
                }
            }
        },
        {
            $group: {
                _id: "$event_id",
                auxdatas: { $push: "$$ROOT" }
            }
        }
    ],
    { allowDiskUse: true }
).forEach((group) => {
    const nav = group.auxdatas.find((x) =>
        [
            "alvinRealtimeNavData",
            "vehicleRealtimeNavData"
        ]
        .includes(x.data_source)
    );

    const local = group.auxdatas.find((x) =>
        [
            "vehicleRealtimeAlvinCoordData",
            "vehicleRealtimeLocalCoordData",
        ]
        .includes(x.data_source)
    );

    // skip if not both found
    if (!nav || !local)
        return;

    const local_x = (local.data_array.find((x) => ["alvin_x", "local_x"].includes(x.data_name)) || {}).data_value;
    
    const local_y = (local.data_array.find((x) => ["alvin_y", "local_y"].includes(x.data_name)) || {}).data_value;

    if (local_x === undefined || local_y === undefined)
        return;

    if (nav.data_array.findIndex((x) => ["local_x", "local_y", "alvin_x", "alvin_y"].includes(x.data_name)) !== -1) {
        print("Realtime nav data already has local_x / local_y, skipping");
        return;
    }

    const insertat = nav.data_array.findIndex((x) => x.data_name === "depth");
    if (insertat === -1)
        return;
    
    nav.data_array.splice(insertat, 0, {
        data_name:  "local_y",
        data_value: local_y,
        data_uom:   "meters",
    });
    nav.data_array.splice(insertat, 0, {
        data_name:  "local_x",
        data_value: local_x,
        data_uom:   "meters",
    });

    db.event_aux_data.replaceOne({ _id: nav._id }, nav);
    db.event_aux_data.deleteOne({ _id: local._id });
});
Clone this wiki locally