Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongoose array with 2 (or more) schema types

Building on the answer to this question, Nested arrays in Mongoose

I am wondering if there is a way to have an array in a mongoose schema that will only accept one of two types of Schema defined documents as elements in the array. What do I mean by this? Consider a schema defined as...

var MyDocSchema = new Schema({
  name: String,
  stuff: [Stuff],
});

Where stuff is defined as

var Stuff = new Schema({
  name: String,
  value: Number,
});

That works, but what if I want my stuff: array to be able to contain Stuff or OtherStuff....

var MyDocSchema = new Schema({
  name: String,
  stuff: [Stuff *or* OtherStuff ],
});

where Stuff is the same as before and OtherStuff is defined as

var OtherStuff = new Schema({
  count: Number,
  when: Date,
});
like image 318
honkskillet Avatar asked Apr 02 '14 04:04

honkskillet


People also ask

What is Mongoose schema types ObjectId?

Types. ObjectId . A SchemaType is just a configuration object for Mongoose. An instance of the mongoose. ObjectId SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.


1 Answers

There are basically two ways to do this:

  1. store Stuff and OtherStuff in another own collection (the same collection), and store only the id of the objects in the field, you can then populate the result. The trick with this solution is that you want to create two mongoose models pointing to the same collection.

    Note: This solution is fine for big and vastly differing Stuff and OtherStuff objects (because of mongoDb storage heuristics), with a low Document count (because population is a slow process). Ultimately if the objects are very different they should have their own field though.

  2. use discriminators. Basically you need three document Schemas for your example (other schemas stay the same):

    // -- Stuff --
    // Please copy from above
    
    // -- OtherStuff --
    // Please copy from above
    
    // MyDocument -
    var MyDocSchema = new Schema({ name: String });
    
    // MyDocStuff - 
    var MyDocStuffSchema = new Schema({ stuff: [Stuff] });
    
    // MyDocOtherStuff - 
    var MyDocOtherStuffSchema = new Schema({ stuff: [OtherStuff] });
    
    var myDoc = new mongoose.Model( 'myDoc', myDocSchema );
    var myDocStuff = myDoc.discriminator( 'myDocStuff', myDocStuffSchema );
    var myDocOtherStuff = myDoc.discriminator( 'myDocOtherStuff', myDocOtherStuffSchema );
    
    // when writing with this method, you need to know which model is relevant
    // isOtherStuff() just checks for _when_ or _count_ fields
    if( isOtherStuff(doc) ) {
        myDocOtherStuff.create(doc);
    } else {
        myDocStuff.create(doc);
    } 
    

Note: this is the solution to use with polymorphic objects which look similar, that are fast for large N in doc.

like image 199
Ron Wertlen Avatar answered Sep 22 '22 02:09

Ron Wertlen