3

I have a document in a mongodatabase

user:{
    name:'bruce',
    surname:'wayne',
    job:'batman',
    email:'onlyifdanger@batman.com',
}

so when user update info, I have to:

  1. query into database if user exist
  2. if exist get the values of the database
  3. compare the values of the database with the form values sent from user
  4. if values from database are equals, discard the opperation
  5. if values from database are diferent, update the values with the form values
  6. close db and sent.response

so in this case if the user sends this:

form.newUserInfo:{
    name:'bruce albert',
    surname:'wayne',
    job:'batman only at night',
    email:'onlyifdanger@batman.com',
}

just update name and job.

Is there any way to do this in less than 6 steps? I'm using nodejs v0.10, mongodb 2.2.3, expressjs and mongoskin v0.5

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
andrescabana86
  • 1,778
  • 8
  • 30
  • 56
  • 1
    If the new values are the same as the old values, what would be the harm in replacing them? Please update your question to include some information on _why_ you are trying to do this, which can then help others to answer your question. – Martin Atkins Mar 18 '13 at 00:19
  • I agree with Martin, what are you gaining with these six steps? If two people edit the record at the same time they're still going to overwrite each other's changes. – robertc Mar 18 '13 at 00:22
  • if the new values are the same as the old values there is no problem to replace them, because is same that old, but is it posible change only the different values?? and the other problem is when the user insert the values at first time... i ahve to check first if exist.. – andrescabana86 Mar 18 '13 at 00:36
  • 3
    Update with upsert=true will insert the record if it doesn't already exist. So you should never need to check if the record already exists - that's not thread-safe anyway. And you should just update with values they are providing, whether they are new or not it doesn't matter - you are doing far more work with your 6 steps when the whole thing can be done with one step. – Asya Kamsky Mar 18 '13 at 01:03
  • what happend if one value is not present, like job that is not required... the update will be job=''?? – andrescabana86 Mar 18 '13 at 01:05

2 Answers2

2

You may have got the info you need from other comments/answers. But this is quite a robust way of upsert the data you have.

Using $findAndModify you can control optimistic concurrency and upsert.

If you wanted to you could find the differences, but if you can be sure the document is the same as when the user opened it, you would use findAndModify to atomically update the document where the values were the same as the document when it was loaded.

The update part in this command updates all the value, but you could easily restrict it based on differences if you wanted to.

The query matches all the values of the document prior to it being modified. This ensures it's not been changed since the user opened it.

db.people.findAndModify( {
   query: {
        name:'bruce',
        surname:'wayne',
        job:'batman',
        email:'onlyifdanger@batman.com',
    },    
   update: {
        name:'bruce',
        surname:'wayne',
        job:'business owner',
        email:'bruce@wayne.com',
    },
   upsert: true
   // uncomment next line to get the updated / new document return
   // ,new : true
} );
sambomartin
  • 6,663
  • 7
  • 40
  • 64
1

It sounds like you're looking to update the specific fields of a result rather than the entire object itself. I.e. if a user only provides update parameters for the name, you only want to update the name in the database. Using your name:'bruce albert' example, the newUserInfo would be

newUserInfo: {
  name: 'bruce albert',
  surname: '',
  job: '',
  email: ''
}

and you don't want to simply upsert with those values, because you'd either wipe the information you already have, or add a duplicate record with less information.

In this case, you can only optimise so far.

  1. query into database if user exists
  2. if it exists get the values of the database
  3. compare the values of the database with the form values sent from user
  4. if values from database are equals, discard the operation
  5. if values from database are different, update the values with the form values
  6. close db and send response

Steps 1 and 2 could be combined, since findOne() (or something to that effect) will return a record matching parameters but only if the object exists. If it doesn't exist, you might want to insert the values passed by the user.

Step 4 can be removed because in essence it's doing nothing anyway.

Step 5 is probably the most important, as you'll have to define how values can be 'different'. Think, do you want to update with job=''? Because that IS 'different' from 'batman', although you might not want to update with that value.

My steps would be

  1. See if the record exists in the database.
    • If it doesn't, INSERT the object and go to step 3
    • If it does, go to step 2
  2. Compare the values in the database object with the values supplied by the user.
    • If the values are different (in ways that you want), update each field as required.
    • If the values are the same then there's nothing to do, go to step 3
  3. Close db and send response to user

Hope this helps.

mattsch
  • 1,454
  • 1
  • 14
  • 18