mlegenhausen,

I tried this and it didn't seem to work correctly.  But then I found your 
workaround <https://github.com/LearnBoost/mongoose/issues/633>.  This code 
is working now:

// in my schema definition:
AccountSchema.statics.findAndModify = function (query, sort, doc, options, 
callback) {
  return this.collection.findAndModify(query, sort, doc, options, callback);
};

// in my model service:
var findOrCreate = exports.findOrCreate = function (data, callback) {
  if (!data.source) {
    return callback(new ParamError('Missing account.source.'));
  }
  if (!data.external_id) {
    return callback(new ParamError('Missing account.external_id'));
  }

  var upsertDoc = new Account(data).toObject();
  delete upsertDoc._id;

  Account.findAndModify({
    source: data.source,
    external_id: data.external_id
  }, [], upsertDoc, {
    "new": true,
    "upsert": true
  }, function (err, doc) {
    if (err) {
      return callback(err);
    }
    if (!doc) {
      return callback();
    } 
    var account = new Account(); 
    account.init(doc, function (err) {
      if (err) {
        return callback(err);
      }
      return callback(null, account);
    }); 
  });
};

Thanks for your help!

On Sunday, July 29, 2012 4:24:16 AM UTC-7, mlegenhausen wrote:
>
> Why you do not use the findAndModify method? This method can create an 
> document when it is not find via the upsert: true parameter. This method 
> has the advantage to be atomic like a transaction and you get no problems 
> when you run multiple node process which execute your findOrCreate method.
>
> Am Sonntag, 29. Juli 2012 03:12:40 UTC+2 schrieb Jaime Morales:
>>
>> Hi,
>>
>> I am running into an issue trying to run multiple findOrCreate methods in 
>> parallel.
>>
>> Here is the code:
>>
>> var findOrCreate = exports.findOrCreate = function (data, callback) {
>>   if (!data.source) {
>>     return callback(new ParamError('Missing account.source.'));
>>   }
>>   if (!data.external_id) {
>>     return callback(new ParamError('Missing account.external_id'));
>>   }
>>
>>   Account.findOne({
>>     source: data.source,
>>     external_id: data.external_id
>>   }, function (err, account) {
>>     if (err) {
>>       return callback(err);
>>     }
>>     if (account) {
>>       return callback(err, account);
>>     }
>>     account = new Account(data);
>>     account.save(function (err) {
>>       return callback(err, account);
>>     });
>>     
>>   });
>>
>> };
>>
>> The issue is that I may have multiple queries for the same 
>> source/external_id combo.  I am using async.parallel to handle them.  But 
>> since the callbacks in mongoose are pushed onto the next tick, I end up in 
>> a situation where 
>>
>>    1. a find is performed (pushing the create to the next tick)
>>    2. another find is performed for the same source/external_id (pushing 
>>    the create to the next tick)
>>    3. a create is performed (for the first find)
>>    4. an attempt is made to create again, but this time a duplicate key 
>>    error is thrown (since I already created that account)
>>    
>> I originally tried to get around this by doing an upsert instead of find 
>> or create, but that didn't work since I need access the the resulting item. 
>>  I am not sure what the best way to handle this scenario is.  any ideas?
>>
>

-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Reply via email to