Jerome
Jerome

Reputation: 1192

How to upsert MongoCollection but keep some values?

Hi, I don't know how to put a good title for it but I'm sure you will understand

So I'm trying to set 2 fields on my Mongo collection when the user click on a button BUT every 60sc I have a method that is running and who make that:

  upsertCollectionMachines = Meteor.bindEnvironment(function() {
      machinesCount = 0;
        var protocol;
        var port;
        Machine.list({
            inspect: true
        }, Meteor.bindEnvironment(function(err, machines) {
            if (typeof machines === "undefined") {
                console.error("Impossible to access 'machines' from 'Machine.list:  '" + err);
            } else {
                machines.forEach(Meteor.bindEnvironment(function(machineInfo) {
                    machinesCount += 1;
                    if (machineInfo.url != null) {
                        var urlToArray = machineInfo.url.split(":")
                        port = urlToArray[urlToArray.length - 1];
                        protocol = "https";
                    } else {
                        port = "2376";
                        protocol = "https";
                    }
                    InfosMachines.upsert({
                        nameMachine: machineInfo.name,
                    }, {
                        nameMachine: machineInfo.name,
                        stateMachine: machineInfo.state,
                        ipAddr: machineInfo.driver.ipAddress,
                        port: port,
                        protocol: protocol
//here I want to add isUsed: false,  
//whoUseIt: "", but I think if I set isUsed true --> after 60s it will be false again right ?
                    });
                }));
                if (apiKeyGenerated == false) {
                    getTheAPIKeyGrafana(function(err, res) {
                        if (!err) {
                            apiKeyGenerated = true;
                            updateDashboard();
                        } else {
                            console.error(err);
                        }
                    });
                }else{
                  updateDashboard();
                }
            }
        }));
    })

Where the important part is the InfosMachines.upsert(). Now I want to set 2 fields like this :

'lockTheMachine': function(nameMachine, nameUser){
        InfosMachines.upsert({
            nameMachine: nameMachine,
        }, {
            nameMachine: nameMachine,
            isUsed: true,
            whoUseIt: nameUser
        });
        //upsertCollectionMachines();
        console.log(nameUser +" has locked the machine: " + nameMachine);
        },

But first it doesn't look likes it add the 2fields to the collection and secondly the 60s interval method will delete them right ?

Thank you for the help

Upvotes: 0

Views: 31

Answers (1)

jordanwillis
jordanwillis

Reputation: 10705

It was a little hard to follow exactly what you are trying to do in your question, but I think I got the main gist of it.

Basically, you want the lockTheMachine() function upsert to only ever set nameMachine, isUsed, and whoUseIt fields and you only want upsertCollectionMachines() to set stateMachine, ipAddr, port, protocol fields on update and only set isUsed and whoUseIt to default values on insert?

You should be able to do that using the below upserts.

Use this upsert inside your upsertCollectionMachines() function.

InfosMachines.upsert({
  nameMachine: machineInfo.name,
}, {
  $set: {
    stateMachine: machineInfo.state,
    ipAddr: machineInfo.driver.ipAddress,
    port: port,
    protocol: protocol
  },
  $setOnInsert: {
    isUsed: false,
    whoUseIt: "",
  }
});

It will always set stateMachine, ipAddr, port, protocol fields regardless if it is inserting or updated, but will only modify isUsed and whoUseIt if it is inserting (therefore, it will not overwrite the values set from the other function).

Use this upsert inside your lockTheMachine() function.

InfosMachines.upsert({
  nameMachine: nameMachine,
}, {
  $set: {
    isUsed: true,
    whoUseIt: nameUser
  }
});

It will only ever insert or update those 2 specific fields (isUsed and whoUseIt).

Now, why does this work? First, we are using update operator expressions (instead of only field:value expressions) which allow you to only update specific fields when needed and using $setOnInsert ensures that we only ever modify those fields on insert only. Note, that if the upsert determines it needs to insert a new document, per the mongodb upsert option behavior, it creates a new document using...

The fields and values of both the <query> and <update> parameters if the <update> parameter contains update operator expressions

This means you don't have to ever actually $set the nameMachine field explicitly in the update expression.

Upvotes: 1

Related Questions