0

I´m trying to save an array on MongoDB using mongoose. Here is my model:

let itemFields = { "name": { "type": "String", "required": true, "unique": true } };

let modelFields = {
    "name": { "type": "String", "required": true, "unique": true },
    "description": { "type": "String" },
    "options": { "type": "Array", "ref": "SelectOptionItem" },
    "company_id": { "type": "ObjectId", "ref": "Company", "required": true },
    "deleted": { "type": "Boolean", "required": true },
    "createdAt": { "type": "Number" },
    "updatedAt": { "type": "Number" }
};

const SelectOptionItem = new mongoose.Schema(itemFields);
const schema = new mongoose.Schema(modelFields);

Later I have the following code to save data:

schema.statics.create = async function(context, data) {
    console.log("Saved data:");
    console.log(data);
    let so = new this(data);
    so.save();
}

Where I get the following log:

 Saved data:
 { name: 'aa',
   description: 'aa',
   options: [ { name: '1' }, { name: '2' } ],
   company_id: '59b2cd9a072e4f28b839aaa0',
   deleted: false,
   createdAt: 1511569192524 }

Finally, this is what I´m getting in the mongo console:

> db.selectoptions.find({});
{ "_id" : ObjectId("5a18b7288c688033a4adcb0c"), "name" : "aa", "description" : "aa", "company_id" : ObjectId("59b2cd9a072e4f28b839aaa0"), "deleted" : false, "createdAt" : 1511569192524, "options" : [ [ { "name" : "1" } ], [ { "name" : "2" } ] ], "__v" : 0 }

Repair that options is being an array of array ([[]]). Later when retrieving that data I´m having problems as I´m expecting a single array.

I need to undestand why mongoose is saving an array of array at options field and how to solve that.

2
  • which version of mongoose you are using ? Commented Nov 25, 2017 at 1:17
  • Mongoose Version 4.11.1. Commented Nov 25, 2017 at 9:35

2 Answers 2

2

Change this line:

"options": { "type": "Array", "ref": "SelectOptionItem" },

By this:

"options": { "type": "Mixed", "ref": "SelectOptionItem" },

Or by this:

"options": [SelectOptionItemSchema],

The second one generate an _id for item

Sign up to request clarification or add additional context in comments.

3 Comments

For some reason options is set to an empty array with this approach in 4.13.1
Thanks Nandu, I have edited my answer, please let me know what you think about it.
Yeah that looks about right but from a schema standpoint, you usually would not put a ref on Mixed type. Please review my answer as well.
1

There are two ways to achieve this.

  • First, by not creating a separate collection for SelectOptionItem
  • Second, by creating a new SelectOptionItem collection and using ref

Using mongoose 4.13.1. You can try this to insert objects into your array without creating a new collection for SelectOptionItem. You can always disable _id property for documents in options if you don't require it.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;

var SelectOptionItemSchema= mongoose.Schema({ "name": { "type": "String", "required": true, "unique": true } })

let modelFields = {
    "name": { "type": "String", "required": true, "unique": true },
    "description": { "type": "String" },
    "options": [SelectOptionItemSchema],
    "company_id": { "type": "ObjectId", "ref": "Company", "required": true },
    "deleted": { "type": "Boolean", "required": true },
    "createdAt": { "type": "Number" },
    "updatedAt": { "type": "Number" }
};

var SelectOptionSchema = mongoose.Schema(modelFields)

var SelectOption = mongoose.model('SelectOption', SelectOptionSchema);

var data = { name: 'aa', description: 'aa', options: [ { name: '1' }, { name: '2' } ], company_id: '59b2cd9a072e4f28b839aaa0', deleted: false, createdAt: 1511569192524 }


var newSelectOption = new SelectOption(data)

If you want to create a collection for SelectOptionItem at any cost then while creating the document you need to send the SelectOptionItem Ids in the array for options. Because ref is similar to a foreign key.

You can use .populate to get the full blown object while querying. Refer to http://mongoosejs.com/docs/populate.html for more querying techniques.

NOTE: I am not sure how accurate this is but you most probably would want to send ObjectId to the ref column.

Note: ObjectId, Number, String, and Buffer are valid for use as refs. However, you should use ObjectId unless you are an advanced user and have a good reason for doing so.

var SelectOptionItemSchema = mongoose.Schema({ "name": { "type": "String", "required": true, "unique": true } })

var SelectOptionItem = mongoose.model('SelectOptionItem', SelectOptionItemSchema);

var firstOptionItem = new SelectOptionItem({name: "1"}); //5a18cfe79a61fd183530d467
var secondOptionItem = new SelectOptionItem({name: "2"}); //5a18d0089a61fd183530d469

let modelFields = {
    "name": { "type": "String", "required": true, "unique": true },
    "description": { "type": "String" },
    "options": [{type: "ObjectId", ref: "SelectOptionItem"}],
    "company_id": { "type": "ObjectId", "ref": "Company", "required": true },
    "deleted": { "type": "Boolean", "required": true },
    "createdAt": { "type": "Number" },
    "updatedAt": { "type": "Number" }
};

var SelectOptionSchema = mongoose.Schema(modelFields)

var SelectOption = mongoose.model('SelectOption', SelectOptionSchema);

var data = { name: 'aa', description: 'aa', options: [ "5a18cfe79a61fd183530d467", "5a18d0089a61fd183530d469" ], company_id: '59b2cd9a072e4f28b839aaa0', deleted: false, createdAt: 1511569192524 }


var newSelectOption = new SelectOption(data)

SelectOption.find({}, function(err, response) { 
    console.log(response)
}).populate('options')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.