Naor
Naor

Reputation: 24063

mongoose relation between models

I am using mongoose and I have two models: Item and Hashtag.
Hashtag model should contain only name and Item model should contain a list of hashtags (represented by ids).
This is what I've done:

var ItemSchema = new Schema({
    hashtags: [ { type: Schema.ObjectId, 'default': null, ref: 'Hashtag' } ],
}); 

var HashtagSchema = new Schema({
    name: { type: String, 'default': '', trim: true },
    items: [{ type: Schema.ObjectId, ref: 'Page' }]
});

This is how I try to create an Item:

   var item = new Item({
        hashtags: ['a', 'b', 'c']
    });
    item.save(function (err, item) {
        if (err) return res.json({ error: err });
        res.json(item);
    });

Unfortunately I get this error:

CastError: Cast to ObjectId failed for value "a,b,c" at path "hashtags"

How can I solve this?

Upvotes: 0

Views: 3029

Answers (1)

mr.freeze
mr.freeze

Reputation: 14062

Since you are using references instead of subdocuments, you need to create the hashtag objects first:

var tagnames = ['a','b','c'];
var hashtags = {}; //for referencing quickly by name later
for (var h in tagnames){
    var tag = new Hashtag({
        name: tagnames[h]
    });
    tag.save(function (err, item) {
        if (err) console.log('error:',err);
        hashtags[item.name] = item; 
    });
}

Once you have the hashtags created, you can reference them::

var item = new Item({
    hashtags: [hashtags.a._id,hashtags.b._id,hashtags.c._id]
});
item.save(function (err, item) {
    if (err) return res.json({ error: err });
    res.json(item);
});

Then you can use populate to automatically turn the object ids into documents:

Item.find({})
    .populate('hashtags')
    .exec(function (err, items) {
        if (err) return handleError(err);
        //items are populated with hashtags
    });

If you are just doing simple tagging, then subdocuments may be a better fit. They allow you to declare and save child documents all in one step. The trade-off is that subdocuments belong exclusively to their parent documents. They are not references so any aggregations on them must be done manually.

Upvotes: 2

Related Questions