Increment a value in a MongoDB field

Hello, I’m trying to increment a value to my “counterEdit” field in my “Tickets” collection every time a ticket is changed.

Surely I have trouble, because when I run my update function, the field value changes to “double” and becomes NaN.

Going to guess that this is not what you think it is in this function, and so this.counterEdit is undefined.
Any addition with undefined always results in NaN and NaN is officially a type of float, which explains the conversion to double in Mongo

I’d need to see more code, at least enough to know what this is supposed to be, to know for sure.

3 Likes

You should use $inc operator for incrementing integer number fields.
For Example:

Products.update(
   { sku: "abc123" },
   { $inc: { quantity: -2, "metrics.orders": 1 } }
)

The update() operation uses the $inc operator to decrease the quantity field by 2 (i.e. increase by -2 ) and increase the "metrics.orders" field by 1 :

7 Likes

Thank you.

I am informed about the doc of $ inc.

I think I used the correct syntax but the value of the field remains 0 after execution of the function.

	updateTicket(ticketId, ticket) {
		Tickets.update(
		{_id: ticketId}, 
		{ $set: {title: ticket.title, content: ticket.content}},
		{ $inc: {counterEdit: 1 }}
		)
	 },

I think you have a problem with your _id field.
I tried to recreate the bug on my end:

Insert a ticket:

db.tickets.insert({title:"title",content:"content",counterEdit:0})
WriteResult({ "nInserted" : 1 })
db.tickets.find({title:"title"})
{ "_id" : ObjectId("5d3ae9f36a5393ea092cd876"), "title" : "title", "content" : "content", "counterEdit" : 0 }

Update:

I tried updating using the string i received from the find result:

db.tickets.update(
    { _id: "5d3ae9f36a5393ea092cd876" }, 
    {
        $set: { title: "new title", content: "new content" },
        $inc: { counterEdit: 1 }
    }
)
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })

No luck, Mongo couldn’t find it. But if I use ObjectId instead:

db.tickets.update(
    { _id: ObjectId("5d3ae9f36a5393ea092cd876") }, 
    {
        $set: { title: "new title", content: "new content" },
        $inc: { counterEdit: 1 }
    }
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

Something was changed! And indeed:

db.tickets.find({})
{ "_id" : ObjectId("5d3ae9f36a5393ea092cd876"), "title" : "new title", "content" : "new content", "counterEdit" : 1 }

The counter and the fields were updated correctly…your query has no problems…

I am guessing you are sending the _id field in the ticketId parameter from the client to the server.
I can’t remember where, but I read that this is dangerous because the _id field is generated by the minimongo on the client, and MongoDB on the server, meaning that you end up with _id’s that do not match!

I would advise to create a specific new field in the ticket collection for the ID and generate it manually, and never use the _id field for operations that go through the client-server communications.
To see if I am right, please put console.log(ticketId) before the call of the method on the client and check if it’s the same id on the database.

1 Like
'submit .js-edit-ticket'(event, instance) {
		event.preventDefault()
		
		const title = event.target.title.value
		const content = event.target.content.value
		**console.log(ticketId)**
		Meteor.call('updateTicket', FlowRouter.getParam('ticketId'),{ title: title, content: content},
				   (err, res) => {
			if(!err) {
				FlowRouter.go('/ticket/:ticketId', {ticketId: FlowRouter.getParam('ticketId')})
			}
		})
	}

My ticket insertion method:

	insertTicket(ticket) {
		let ticketDoc = {
			title: ticket.title,
			content: ticket.content,
			createdAt: new Date(),
			ownerId: this.userId,
			open: true,
			counterEdit: 0
		};
		
		Tickets.insert(ticketDoc);
	},

So, I do not use a manually created id. Can this be the problem?

Yes, I prefer creating my own id’s and do not use the MongoDB ones. It’s easier to manage and control…
But anyway, your ticketId is undefined, so there is your problem. you are sending undefined value to the query field and mongo can’t find it.
I would advise making yourself familiar with the mdg:validated-method package. It will prevent problems like that in the future and will secure your Meteor Methods to receive a sanitized and validated input.

2 Likes

The line to update the title and content since $set works

Sorry but this part is just wrong. _ids are the most secure (and convenient) way to communicate client->server.

It works fine because Meteor only uses strings for _ids instead of Mongo’s ObjectID and Meteor guarantees that the generated ID will be the same on client and server.

I think you’ve nailed it here

3 Likes

@alkapoun, you have a mistake in this code:

    updateTicket(ticketId, ticket) {
        Tickets.update(
            {_id: ticketId}, 
            { $set: {title: ticket.title, content: ticket.content}},
            { $inc: {counterEdit: 1 }}
        )
    },

You are sending the $inc as a third parameter to the update() function. Instead, $inc needs to be inside the 2nd parameter along with $set:

   updateTicket(ticketId, ticket) {
       Tickets.update(
           {_id: ticketId}, 
           {
               $set: {title: ticket.title, content: ticket.content},
               $inc: {counterEdit: 1 }
           }
       )
   },
2 Likes