2

So I'm creating a REST API, and when someone calls a method to return data I get the data from an external API, check if the ID of the data already exists and if it does, update it, and if not create it.

The problem is that if another request were to come in for the same resource, my function looks up the data, and finds that it does not exist (yet), however by the time it's got to the save call, the save from the previous function has completed, so the save fails (some fields must be unique).

I've currently setup a queue using nodejs async and a single worker. This works however I think it's really going to cause performance issues!

Does anyone know how I can do this in a way thats not going to cause performance issues?

var storeData = function(APIResponse, id, callback){

  Record.findOne({ id: id }, function(err, data) {

    if(data === null) {
      //No record, so lets create one

      var data = {};
      data.id = id;
      data.title = APIResponse.title;

      var dataToSave = new Record(data);

    } else {
      //data exists in store, lets update it

      data.title = APIResponse.title; //Update title
      var dataToSave = data;

    }

    dataToSave.save(function(err, doc) {
      if(err) {throw err;}

      //A callback to continue with some other processes
      callback(null, APIResponse, doc);

    });
  });

};

Any ideas/suggestions would be really appreciated, Many Thanks

Ross
  • 1,425
  • 1
  • 19
  • 38
  • In your REST call what do you pass into `id` if you assume data creation? – Vitalii Zurian Dec 11 '14 at 15:01
  • Literally a unique ID for the resource. (e.g. 10191). The idea is that the data is cached for later on – Ross Dec 11 '14 at 15:03
  • But how do you know ID if you are creating a new item? Do you pass null there or some special string or what? Is it always an ID? – Vitalii Zurian Dec 11 '14 at 15:07
  • The REST call will always have an ID attached. So the user may search for this resource and when they select it, the call will contain the ID that is fetched from the external API. (I know the ID because i get it from an external API call that happens beforehand.) – Ross Dec 11 '14 at 15:11
  • 1
    Ah, understood. Did you have a look at this answer? http://stackoverflow.com/a/16362833/970721 – Vitalii Zurian Dec 11 '14 at 15:18
  • possible duplicate of [MongoDB atomic "findOrCreate": findOne, insert if nonexistent, but do not update](http://stackoverflow.com/questions/16358857/mongodb-atomic-findorcreate-findone-insert-if-nonexistent-but-do-not-update) – Vitalii Zurian Dec 11 '14 at 15:34

1 Answers1

1

Why not just upsert?

var storeData = function(APIResponse, id, callback) {
  var record = {
    id: id,
    title: APIResponse.title
  };

  Record.findOneAndUpdate({ id: id }, record, { upsert: true }, function(err, doc) {
      if(err) { throw err; }
      callback(null, APIResponse, doc);
  });
};
Timothy Strimple
  • 22,920
  • 6
  • 69
  • 76