6

Trying to use findOneAndUpdate() to change an object inside an array within MongoDB. The documentation for mongoDB's nodeJS driver isn't clear to me. The document looks like this:

{
  _id:ObjectID(),
  some: string,
  body: string,
  steps:[
   [0]{name: "foo", state:"Q"},
   [1]{name: "bar", state:"Q"},
   [n]{name: "fooBar", state:"Q"}
 ]
}

I need to lookup the steps name (foo) and set it's state to P (for in progress) and then to C (for complete) when the task has been executed or E when it errors.

I'll then need to also grab the name of the next step to.

Finding the document isn't hard as I will have the _id already, it's the update portion that's getting me.

EDIT: This is what I've got so far

  async msg => {
    const _id = msg.content.toString();
    const id = new objectId(_id);
    logger.info(`${name} consumer - Recieved new task, fetching details`, {
      id
    });
    try {
      const jobDetails = await collection.findOneAndUpdate(
        { _id: id },
        {
          /**/
        }
      );
      await consumer.task(jobDetails);
    } catch (e) {}
  },

It's the framework for a rabbitMQ consumer

Alistair Hardy
  • 397
  • 1
  • 4
  • 16
  • Show us the code you're working on – Daniyal Lukmanov Jun 10 '19 at 13:18
  • Added existing code, though it's incomplete. The area I need is in the /* */ – Alistair Hardy Jun 10 '19 at 13:26
  • So basically you did nothing in terms of writing the update query apart from stating that docs are not clear. Sounds like "write it for me" question. Take a look at https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/ it has some almost copy-pasteable examples for your usecase. – Alex Blex Jun 10 '19 at 13:34
  • No, I'd read that, but I if you don't understand the documentation, it's hard to apply it to your use case. – Alistair Hardy Jun 10 '19 at 14:02

1 Answers1

12

I don't know how would you choose wich letter to set - P, C or E, because it is not quite clear, but for replacing a value in mongoDB it would look like this (let's say for 'P'):

myCollection.findOneAndUpdate({"_id": docId, "steps.name": "foo"},
    {$set: {"steps.$.state": "P"}})
  1. Find the document you need to change.
  2. Find the object inside the array "steps.name": "foo". And you get the position of that object in array.
  3. You're setting new value for the object's property ( $ reflects the position).
Daniyal Lukmanov
  • 1,149
  • 10
  • 21
  • Thanks, that did the trick. I know when to set each state. P is set when the consumer receives the task, C when it completes the job and E when it errors (so in the catch(e){...} ). – Alistair Hardy Jun 10 '19 at 14:04
  • thanks, dude! I was looking for a solution like this. – tmsnvk Feb 01 '21 at 09:20