Keeping distinct status in an array using trip lifecycle

Viewed 17

I want to create a status timeline. Similar to what we have with Uber or Lyft and I have my model schema to update so that I can keep track.

New request, Driver accepts, arrives, starts trip and ends trip.

I am keeping track of all these by updating the database and putting the time of update.

The problem I have now is it is possible to enter same entry eg

arrive pickup twice with different timestamp.

I do not want this to happen.

Once you arrive pickup, you cannot arrive pickup again, the most you can do should be able to return to the previous stage new request.

Here is my Schema

const StatusDataSchema = new Schema({
    status: {
        type: SchemaTypes.String,
        enum: [
            'new',
            'acknowledged',
            'assigned',
            'start',
            'arrived',
            'end',
            'rejected',
            'cancelled',
            'completed'
        ],
        unique: true,
        default: 'new'
    },
    message: {
        type: SchemaTypes.String,
        default: 'You created a new request'
    },
    createdAt: {
        type: SchemaTypes.String,
        required: false,
        default: Date.now.toString()
    },
    updatedAt: {
        type: SchemaTypes.Date,
        required: false,
        default: null
    }
},
{
    toJSON: {
        virtuals: true,
        versionKey: false,
        transform: function (_, ret, __) {
            const { _id, __v, ...rest } = ret;
            return rest;
        }
    }
});

const DeliverySchema = SchemaFactory({
    pickup: { type: PickupSchema, required: true },
    dropoff: { type: DestinationSchema, required: true },
    status: {
        type: SchemaTypes.String,
        enum: [
            'new',
            'acknowledged',
            'assigned',
            'toPickup',
            'arrived',
            'start',
            'end',
            'rejected',
            'cancelled',
            'completed'
        ],
        unique: true,
        default: 'new'
    },
    statusData: [StatusDataSchema],
})

Then I create like this

public async createReq(user: string, body: TripDTO) {
        if (user !== body.user.id)
            throw new ActionNotAllowedError(
                'You cannot create a trip on the behalf of another user'
            );
        const data = await this.create({
            ...body
        });

        return data;
    }

and I update like this

public async updateReq(id: string, body: StatusDeliveryDTO) {
        var message = '';
        var cancelReason = null;
        var rejectReason = null;
        var name = '';

        if (body.driver == null) {
            // do something
            name = 'System';
        } else {
            name = body.driver.firstName;
        }
        if (body.status == 'assigned') {
            message = `${name} has been assigned to you`;
        } else if (body.status == 'new') {
            message = 'You created a new request';
        } else if (body.status == 'toPickup') {
            message = `${name} is heading to your pickup location`;
        } else if (body.status == 'arrived') {
            message = `${name} has arrived your pickup`;
        } else if (body.status == 'pickup') {
            message = `${name} has picked`;
        } else if (body.status == 'start') {
            message = `${name} started`;
        } else if (body.status == 'arrived') {
            message = `${name} has arrived`;
        } else if (body.status == 'completed') {
            message = `${name} has completed`;
        } else if (body.status == 'rejected') {
            message = `${name} has rejected your request`;
            rejectReason = body.reason;
        } else if (body.status == 'cancelled') {
            message = `${name} has canceled your request`;
            cancelReason = body.reason;
        } else {
            message = body.status;
        }
        const data = await this.updateWithOperators(id, {
            $push: {
                statusData: {
                    status: body.status,
                    message: message,
                    createdAt: Date.now().toString()
                }
            },

            cancelReason: cancelReason,
            rejectReason: rejectReason,
            ...body
        });
        await NotificationService.dispatchTimeline(data.user.id, message);
        return data;
    }

The create function uses mongoose model.create while update uses model.findOneAndUpdate

How can I avoid the duplicate and keep a streamlined timeline.

Further code can be provided on request.

0 Answers
Related