Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Mongoose model without creating a collection in MongoDB?

Tags:

mongoose

I would like to only have a versioneditems collection in MongoDB but I need to register both the VersionedItem model and the ItemPatch model because I need to create ItemPatches to populate a VersionedItem.

There will be no separate ItemPatch documents (they are embedded in a VersionedItem). The code below is working except for the fact that an extra collection is created in MongoDB:

src/models/versionedItemFactory.js

const VersionedItemSchema = require('../schemas/VersionedItem');

module.exports = (db) => {
  var VersionedItemModel = db.model('VersionedItem', VersionedItemSchema);

  return VersionedItemModel;
};

src/models/itemPatchFactory.js

const ItemPatchSchema = require('../schemas/ItemPatch');

module.exports = (db) => {
  var ItemPatchModel = db.model('ItemPatch', ItemPatchSchema);

  return ItemPatchModel;
};

src/schemas/util/asPatch.js

var mongoose = require('mongoose');

module.exports = function _asPatch(schema) {

  return new mongoose.Schema({
    createdAt: { type: Date, default: Date.now },
    jsonPatch: {
      op: { type: String, default: 'add' },
      path: { type: String, default: '' },
      value: { type: schema }
    }
  });
};

src/schemas/Item.js

var mongoose = require('mongoose');

module.exports = new mongoose.Schema({
  title: { type: String, index: true },
  content: { type: String },
  type: { type: String, default: 'txt' }
}, { _id: false });

src/schemas/ItemPatch.js

var asPatch = require('./util/asPatch');
var ItemSchema = require('./Item');

module.exports = asPatch(ItemSchema);

src/schemas/VersionedItem.js

var mongoose = require('mongoose');
var ItemPatchSchema = require('./ItemPatch');

module.exports = new mongoose.Schema({
  createdAt: { type: Date, default: Date.now },
  patches: [
    {
      createdAt: { type: Date, default: Date.now },
      jsonPatch: { type: ItemPatchSchema }
    }
  ]
});

Then registering like so:

  db.once('open', function() {
    require('./models/itemPatchFactory')(db);
    require('./models/versionedItemFactory')(db);
  });

I need to register the ItemPatch model via itemPatchFactory because I want to be able to populate a versioned item like so:

var itemPatch = new db.models.ItemPatch({
  jsonPatch: {
    op: 'add',
    path: '',
    value: { 
      title: 'This is a title',
      content: 'This is content',
      type: 'txt'
    }
  }
});

var itemPatch2 = new db.models.ItemPatch({
  jsonPatch: {
    value: { 
      title: 'This is a title 2',
      content: 'This is content 2'
    }
  }
});

var versionedSomething = new db.models.VersionedItem();
versionedSomething.patches.push(itemPatch);
versionedSomething.patches.push(itemPatch2);

versionedSomething.save(function (err, result) {
  if (err) throw err;

  console.log('result:', result);
});

This successfully creates the versioned item with the 2 patches in it, but an (empty) itempatches collection is created in MongoDB and I'd like to avoid that.

like image 317
justin Avatar asked Jul 31 '16 15:07

justin


People also ask

Can we create Mongoose model without schema?

Its not possible anymore. You can use Mongoose with the collections that have schema and the node driver or another mongo module for those schemaless ones.

Does Mongoose model create collection?

Mongoose never create any collection until you will save/create any document.

How do you use Mongoose without defining a schema?

To use Mongoose without defining a schema, we can define a field with the Mixed data type. const Any = new Schema({ any: Schema. Types. Mixed });


2 Answers

You can't create a Model without a corresponding collection, but I don't think you actually need to in order to do what you want.

You can simply create a javascript object for the child and push it to the parent collection. See this snippet from the Mongoose docs (https://mongoosejs.com/docs/subdocs.html)

var Parent = mongoose.model('Parent');
var parent = new Parent;

// create a comment
parent.children.push({ name: 'Liesl' });
var subdoc = parent.children[0];
console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' }
subdoc.isNew; // true

parent.save(function (err) {
  if (err) return handleError(err)
  console.log('Success!');
});

You can create a Schema for the subdocument, however. That will let you enforce the structure when reading/writing from the parent collection:

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

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});
like image 158
Dov Rosenberg Avatar answered Oct 04 '22 18:10

Dov Rosenberg


You can use the mongoose Schema options - autoCreate: false, autoIndex: false to not create the mongodb collection.

[1] https://mongoosejs.com/docs/guide.html#autoIndex

like image 43
Vineet Bhatia Avatar answered Oct 04 '22 18:10

Vineet Bhatia