2

As the question states, I'm failing to get this update operation to work.

My scenario:

I have an Event, a Ticket and a TicketPurchase. The Event and TicketPurchase have Ticket arrays as properties.

What I need to achieve:

  1. Update the validated property of a particular Ticket in the ticket array of the TicketPurchase from true/false.

  2. Decrement the total_quantity property of the same ticket from 1. in the master Event table.(all tickets in a TicketPurchase are copies of tickets in the master Event table)

Almost all my experience as a programmer has been spent working with MySQL, so I am still very much a beginner in the NoSQL world.

What I have tried:

  1. Checked the docs
  2. Spent some time on S/O and this proved to be the most relevant answer, but I can't get this solution to work.
  3. Interchanged my usages of id and _id, putting operators like $set in and out of ' ' marks, and all other similar configurations, nothing will give.

ticket.js

const TicketSchema = new Schema({
type : {type: String},
total_quantity : {type: Number},
price : {type: String},
limit_per_order: {type: Number},
start_date: {type: Date},
end_date: {type: Date},
description: {type: String},
validated: {type: String, default: 'false'}
});

event.js

const EventSchema = new Schema({

title: {type: String},
location: {type: String},
start_date: {type: Date},
start_time: {type: String},
end_date: {type: Date},
end_time: {type: String},
description: {type: String},
organizer_name: {type: String},
organizer_about: {type: String},
cover_picture: {type: String},
tickets: [{type: Schema.Types.ObjectId, ref: 'Ticket'}],
access_code: {type: String, default: shortid.generate}

});

ticketPurchase.js

const TicketPurchaseSchema = new Schema({
user: {type: Schema.Types.ObjectId, ref: 'User'},
event: {type: Schema.Types.ObjectId, ref: 'Event'},
tickets: [{type: Schema.Types.ObjectId, ref: 'Ticket'}],
time_stamp: {type: Date}

});

update.js

for(var x of ticketPurchase.tickets){
                //console.log(x);

                if(x.id === ticket_id && x.validated === 'false'){
                    console.log('ticket not validated. Update');

                    TicketPurchase.update(
                        {_id: ticket_purchase_id, 'tickets._id': ticket_id},
                        {'$set':{
                            'tickets.$.validated': 'true'
                        }},
                        function (err){
                            console.log('updated validated');
                            if(err){console.log(err);}
                        }
                    );

                    Event
                    .update({_id: event_id, "tickets._id": x.id},
                    {$inc : {"tickets.$.total_quantity" : -1}});

                    console.log('updated ticket.total_qty');

                    payload['success'] = 'true';

                }else if(x.id === ticket_id && x.validated === 'true'){
                    console.log('ticket validated');
                    payload['success'] = 'false';
                    payload['message'] = 'Ticket already validated.';
                }


   }
BiGGZ
  • 503
  • 4
  • 17

1 Answers1

3

At first, here is a short example of how you could avoid cycles and do everything with only mongoose methods:

TicketPurchase.findById(purchaseId, (err, ticketPurchase) => {

    Ticket.update({ _id: { $in: ticketPurchase.tickets }, _id: ticket_id, validated: 'false' },
        { $set: { validated: 'true' }, $inc: { total_quantity: -1 } }, 
        (err, outcome) => { 
            console.log(`The number of validated tickets for the Purchase #${purchaseId} is ${outcome.nModified}`); 
    }); 
});

Here it does everything in the same operation: finds the ticket which belongs to the purchase and isn't validated yet, thereafter it sets the validated property to 'true' and decrements the quantity. Finally, you'll get the total number of modified records.

In your example I can't see that you've populated your tickets in the purchaseTicket. To iterate through ticket objects in the manner you wrote, you'd be compelled to populate it for their parent entity since the property ticketPurchase.tickets contains only references. The expression would look like: TicketPurchase.findById(purchaseId).populate('tickets').then(purchase => { ... }) Where purchase has the property tickets filled up with its ticket objects instead of merely id objects.

Adding to that, you seem not to have to update tickets in the Event schema since you can do it directly in the Ticket schema (just like I did in my example overhead) since all the references eventually point out to their objects in the schema.

Oleg Safarov
  • 2,325
  • 14
  • 19