3

Im trying to figure out how to toggle the boolean value of "active" in the example from true to false or false to true based on the value existing in the document. So if its true, change it to false and if its false, change it to true. Example array.

[{ _id: 59cb78434436be173e038aaa, active: true, title: 'One' },
{ _id: 59cb78434436be173e038aab, active: false, title: 'Two' },
{ _id: 59cb78434436be173e038aac, active: false, title: 'Three' }]

const todos = db.collection('todos');

const active = !active;
await todos.findOneAndUpdate({ _id: ObjectID(args.id) },
{ $set: { active: active } }, function(err, doc) {
                if (err) {
                    throw err;
                } else {
                    console.log('Updated');
                }
            });

I cant set this directly by passing true or false to active { $set: { active: true }}. How would I test the value and return the opposite?

Thanks

armand
  • 693
  • 9
  • 29

1 Answers1

1

At the moment there is no $toggle operator in MongoDB, so it is impossible to make such switch operation atomic. But there is some kind of workaround for this functionality. First of all you need to replace your boolean with the number. Then instead of trying to replace it with the opposite value you should just increment it every time.

todos.findOneAndUpdate({_id: ObjectId(args.id)}, {$inc:{ active: 1}});

So you see that everytime it will be $incremented by 1 and it means it will always switch from even number to odd.

The next step is to modify your 'get' query in this way:

todos.find({'active' : { '$mod' : [ 2, 1 ] });

It will return all documents where 'active' field is now odd number, which you can consider like true for example, or vice versa.

Artem Arkhipov
  • 7,025
  • 5
  • 30
  • 52
  • Thanks @artem for taking the time to answer. That solutions worked as far as findOneAndUpdate(). I didn't need $mod b/c graphql was handling that but I was happy to learn it. In the end, doing it as you suggested, required me to modify a schema field from bool to str so I went with ```const todos = db.collection('todos'); const oldStatus = await todos.findOne({ _id: ObjectID(args.id) }); const newStatus = !oldStatus.active; await todos.findOneAndUpdate({ _id: ObjectID(args.id) }, { $set: { active: newStatus } }); return await todos.find().toArray();``` Is there a better way to do this? – armand Sep 27 '17 at 16:05
  • Why string instead of number? And I actually don’t clearly understand what solution you have finally chosen? – Artem Arkhipov Sep 27 '17 at 16:20
  • Get the field i want, todo.active, with a query. Create a new var set to toggled value of the field, newValue = !todo.active. Then update the original doc with the new value. Not atomic, and two round trips, so I hoped there might be another way to work that. – armand Sep 27 '17 at 20:57