2

Background:

I have no control over a post event coming to my DB document called Things. When a post comes in, I've written a function called findOrCreate().(which will either find or create a record(object?) in the Things document). To reduce redundancy, I want to use the 3rd party POST payload field nuid to replace the default _id of that record(object).

Question:

How can I properly replace the _id with the payloads field called nuid?

example payload:

curl -H "Content-Type: application/json" -X POST -d '{"participant":{"nuid":"98ASDF988SDF89SDF89989SDF9898"}}' http://localhost:9000/api/things

Schema

'use strict';

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var ThingSchema = new Schema(
  {nuid: String}
);

module.exports = mongoose.model('Thing', ThingSchema);

thing.controller.js

//*currently this function will have both _id and a nuid (which works but not desirable)
exports.findOrCreate = function(req, res) {

  var query = {"nuid": req.body.participant.nuid};
  var update = {nuid: req.body.participant.nuid};

  Thing.findOneAndUpdate(
      query,
      update,
      {upsert: true},
      function(err, thing){
        console.log(thing, "thing");
        console.log(err, "err");
        if(!thing) {
          Thing.create(req.body.participant, function(err, thing) {
            if(err) { return handleError(res, err); }
          });
        };
        if(err){return handleError(res, err); }
      }
  );
});

thing/index.js

var express = require('express');
var controller = require('./thing.controller');

var router = express.Router();

router.get('/', controller.index);
router.get('/:id', controller.show);
router.post('/', controller.findOrCreate);
router.put('/:id', controller.update);
router.patch('/:id', controller.update);
router.delete('/:id', controller.destroy);

module.exports = router;

I found a reference but I still don't understand on how to use it properly given the model happens before the payload Stack Reference

Community
  • 1
  • 1
Armeen Moon
  • 18,061
  • 35
  • 120
  • 233

1 Answers1

1

You can set the value of _id to whatever you want here and do it with "upsert" as well. It's just a matter of using $setOnInsert in the update statement:

var thingSchema = new Schema({
  "_id": String
},{ "_id": false });

var Thing = mongoose.model('Thing',thingSchema);


Thing.findByIdAndUpdate("98ASDF988SDF89SDF89989SDF9898",
  { "$setOnInsert": { "_id": "98ASDF988SDF89SDF89989SDF9898" } },
  { "upsert": true },
  function(err,doc) {
    if (err) throw err;
    console.log(doc);
  }
)

And that creates a new document if the _id does not exist or applies an update ( in the example nothing would be updated, just matched and returned ) to the document matched.

If you have any other data you want to update use $set or other operators for the fields you want to alter other than _id.


As an alternate to generating the UUID from a client API ( or as a safety ) you could use something like node-uuid and plug the generation into the schema:

var thingSchema = new Schema({
  "_id": { "type": String, default: function genUUID() { uuid.v1() } }
},{ "_id": false });

var Thing = mongoose.model('Thing',thingSchema);


Thing.findOneAndUpdate(
  { "uname": "sam" },
  { "$set": { "uname": "sam" } },
  { "upsert": true },
  function(err,doc) {
    if (err) throw err;
    console.log(doc);
  }
)

In that way even when an _id is not supplied for an operation then something will be created. Trivial example here, but it makes the point of setting a default.

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135