Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly initialize documents in mongoose collection

Please, correct me if my design is not recommended:

I have a model for blog posts with a field "category". I want the user to be able to type the category (with typeahead) and, if the category isn't there, the user would be able to create it. However, in order to prevent unorganized entries, I want to populate the field "category" with a list of categories.

Question is, should I use field "category" as an array or as a sub-document referenced to another model called "Category"? I am assuming the latter would be the recommended design, because it avoids code replication and makes easy the interaction necessary for the user to add a new category.

Now, if I use it with sub-documents, how could I initialize the model "Category" with a list of categories on server startup?

like image 932
igorauad Avatar asked Aug 02 '14 03:08

igorauad


2 Answers

Why don't you use something like this.

//Category schema
//Store all the categories available in this collection
var categorySchema=new Schema({
     _id:String,//name of category
     description:String
     //other stuff goes here
})
mongoose.model(categorySchema, 'Category')

//blog post schema
var postSchema=new Schema({
    //all the relevant stuff
    categories:[{type:String,ref:'Category'}]
})

Now whenever posting a blog post, check if the categories given are already present in the Category collection. This will be fast as we are using the category name(_id) as the index itself. So for every new category you should insert in the Category collection and then insert the blog post. This way you can populate the categories array if required.

To initialise the categories, it can be done by parsing a JSON file which is more readable . The file should be parsed only when we set off with an empty database i.e when we drop the Categories collection

Create a Categories.json file. Contents of Categories.json:

[
    {
      _id:'Category1',//name of category
     description:'description1'
     ...
    },
    {
      _id:'Category2',//name of category
     description:'description2'
     ...
    },{
      _id:'Category3',//name of category
     description:'description3'
     ...
    }
    ...
]

To read the data from file

fs=require('fs');
var buildCategories=fs.readFile(<path to Categories.json>,'utf8',function(err,data){          

    if (err) {
        //logger.error(err);
        return ;
    }
    var datafromfile=JSON.parse(data);
    data.forEach(function(obj){
       var catOb=new Category(obj)
       obj.save(function(err,doc){..});
    })
});
//To initialize when the Category collection is empty
Category.findOne({},function(err,doc){
    if(!doc){
       //Collection is empty
       //build fomr file
       buildCategories();
    }
});
//Or you can just manually call the function whenever required when server starts
buildCategories();

You could argue that you can import a csv file. But this was how I did for my project.

like image 158
ma08 Avatar answered Nov 15 '22 04:11

ma08


In my case instead of buildCategories - I've added schema method and just import initialData from json file (no need to fs.readFile).

Category.methods = {
async setInitialData() {
    return this.collection.insertMany(initialData, err => {
        if (err){
            return console.error(err);
        }
        console.log("Initial documents inserted to Category Collection");
    });
}}

Then in the controller:

Category.findOne({}, async (err,doc) => {
if(!doc){
    const category = new Category();
    await category.setInitialData();
}});
like image 27
Дмитрий Дорогонов Avatar answered Nov 15 '22 03:11

Дмитрий Дорогонов