Rodrigo Oliveira
Rodrigo Oliveira

Reputation: 785

Mongoose Insert many to one

I need to help! I'm creating a website with nodejs and mongo for learning.

I have a problem that I know the best way to do it. I have two collections codes and tag into table codes I have the tags field is array of tags.

CodeModel:

var CodeSchema   = new Schema({
    title:  { type: 'String', required: true },
    text:   { type: 'String', required: true },
    url:    { type: 'String', required: true },
    uri:    String,

    createdAt: { type: Date, default: Date.now },
    updatedAt: { type: Date, default: Date.now },

    owner: {
        type: Schema.ObjectId,
        ref: 'User'
    },

    tags:   [
        {
            type: Schema.ObjectId,
            ref: 'Tag'
        }
    ]

});

CodeSchema.pre("save", function (next) {
    // if create for first time
    if (!this.created_at) {
        this.created_at = Date.now();
    }

    next();
});

module.exports = mongoose.model('Code', CodeSchema);

And My Tag Model:

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

var TagSchema = new Schema({
    name: 'string'
});

module.exports = mongoose.model('Tag', TagSchema);

when I get the result in my rest I got it:

[
  {
    "_id": "5540f557bda6c4c5559ef638",
    "owner": {
      "_id": "5540bf62ebe5874a1b223166",
      "token": "7db8a4e1ba11d8dc04b199faddde6a250eb8a104a651823e7e4cc296a3768be6"
    },
    "uri": "test-save",
    "url": "http://www.google.com.br/",
    "text": " hello  ",
    "title": "testing...",
    "__v": 0,
    "tags": [
      {
        "_id": "55411700423d29c70c30a8f8",
        "name": "GO"
      },
      {
        "_id": "55411723fe083218869a82d1",
        "name": "JAVA"
      }
    ],
    "updatedAt": "2015-04-29T15:14:31.579Z",
    "createdAt": "2015-04-29T15:14:31.579Z"
  }
]

This I populate into database, I don't know how I insert it, is there any way automatic with mongoose that to do it or I need to create by myself? I am testing with this json:

{
  "url": "http://www.google.com.br/",
  "title": "Test inset",
  "text": "insert code",
  "tags": [
    "ANGULAR",
    {
        "_id": "55411700423d29c70c30a8f8",
        "name": "GO"
    }
  ]
}

I need to do a insert of tags, if I have id or not. Do I need to create it or has way to do it automatically? and how can I do it?

Sorry my english =x

Upvotes: 1

Views: 2630

Answers (2)

Jason Cust
Jason Cust

Reputation: 10909

Generally speaking to create and save a document in a mongo database using mongooseJS is fairly straightforward (assuming you are connected to a database):

var localDocObj = SomeSchemaModel(OPTIONAL_OBJ); // localDocObj is a mongoose document
localDocObj.save(CALLBACK); // save the local mongoose document to mongo

If you have an object that is of the same form as the schema, you can pass that to the constructor function to seed the mongoose document object with the properties of the object. If the object is not valid you will get an invalidation error passed to the callback function on validate or save.

Given your test object and schemas:

var testObj = {
  "url": "http://www.google.com.br/",
  "title": "Test inset",
  "text": "insert code",
  "tags": [
    "ANGULAR",
    {
      "_id": "55411700423d29c70c30a8f8",
      "name": "GO"
    }
  ]
};

var codeDoc = Code(testObj);
codeDoc.save(function (err, doc) {
  console.log(err); // will show the invalidation error for the tag 'Angular'
});

Since you are storing Tag as a separate collection you will need to fetch/create any tags that are string values before inserting the new Code document. Then you can use the new Tag documents in place of the string values for the Code document. This creates an async flow that you could use Promises (available in newer node releases) to manage.

// Create a promise for all items in the tags array to iterate over
// and resolve for creating a new Code document
var promise = Promise.all(testObj.tags.map(function(tag) {
  if (typeof tag === 'object') {
    // Assuming it exists in mongo already
    return tag;
  }

  // See if a tag already exists
  return Tag.findOne({
    name: tag
  }).exec().then(function(doc) {
    if (doc) { return doc; }

    // if no tag exists, create one
    return (Tag({
      name: tag
    })).save(); // returns a promise
  });
})).then(function(tags) {
  // All tags were checked and fetched/created if not an object
  // Update tags array
  testObj.tags = tags;

  // Finally add Code document
  var code = Code(testObj);
  return code.save();
}).then(function(code) {
  // code is the returned mongo document
  console.log(code);
}).catch(function(err) {
  // error in one of the promises
  console.log(err);
});

Upvotes: 1

codeofnode
codeofnode

Reputation: 18629

You can do it like

var checkNewTagAndSave = function(data, doc, next){ // data = req.body (your input json), doc = mongoose document to be saved, next is the callback
    var updateNow = function(toSave, newTags){
      // save your mongoose doc and call the callback.
      doc.set(toSave);
      doc.save(next);
    };
    var data = req.body;
    var tagsToCreate = [];
    var tagids = [];
    data.tags.forEach(function(tag, index){
      if(typeof(tag) == 'string') {
        tagsToCreate.push({ name: tag });
      } else tagids.push(tag._id);
    });
    data.tags = tagids;
    if(tagsToCreate.length === 0) updateNow(data);
    else {
      mongoose.model('tag').create(tagsToCreate, function(err, models){
        if(err || !models) return next(err);
        else {
          models.forEach(function(model){
            data.tags.push(model._id);
          });
          updateNow(data, models);
        }
      });
    }
};

Hope code is reflecting its logic itself

usage :

after you have found your Code document say aCode

just call

checkNewTagAndSave(req.body, aCode, function(err, doc){
   //end your response as per logic
});

Upvotes: 0

Related Questions