justin
justin

Reputation: 3607

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

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.

Upvotes: 8

Views: 3885

Answers (2)

Dov Rosenberg
Dov Rosenberg

Reputation: 805

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
});

Upvotes: 2

Vineet Bhatia
Vineet Bhatia

Reputation: 2533

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

Upvotes: 2

Related Questions