How to define a model & method in mongoose midleware? - node.js

I'm a newbie in mongodb and nodejs. I create a schema such as :
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ContactSchema = new Schema({
name : String,
email: String,
number : String
});
ContactSchema.methods.selectAll = function (callback){
console.log("I got list contact");
ContactModel.find({}).exec(function(err,items){
if(err)
console.error(err.stack);
else{
var notify = {
'message' : 'select all document successfully',
'data' : items,
'status' : 1
};
console.log(notify);
callback();
};
});
};
var ContactModel = mongoose.model('contactlist',ContactSchema);
module.exports = ContactModel;
Assume that I have connected to database with 'mongodb://localhost:27017/contactlist'. It has a database name contactlist, a collection contactlist with some documents
> db.contactlist.find({})
{ "_id" : ObjectId("576e8ac6d68807e6244f3cdb"), "name" : "Tome", "email" : "Tome#gmail.com", "number" : "333-333-333" }
{ "_id" : ObjectId("576e8b4fd68807e6244f3cdc"), "name" : "Trace", "email" : "Trace#gmail.com", "number" : "444-444-444" }
{ "_id" : ObjectId("576e8b4fd68807e6244f3cdd"), "name" : "Tuker", "email" : "Tuker#gmail.com", "number" : "555-444-777" }
>
My Question:
What does exactly 'ContactModel' in mongoose.model('ContactModel',ContactSchema); stand for? It is a name self-define or exactly name of collection in db?
I want to create a method for model ( crud task )
ContactSchema.methods.selectAll = function (){
// code here
}
This method can select all documents of a collection in mongo but my ContactModel.find function return null items.
$ node server
development server is running at 127.0.0.1 port 3000
I got list contact
{ message: 'select all document successfully',
data: [],
status: 1 }
undefined
I mean when I use find api of mongoose. How to do that?

Glad you already had solved your problem somehow. But this is just to address the root cause of problem the problem you faced. Hoping other find it helpful.
I think you have created a database named contactlist and a collection named contactlist before mongoose did it. And mongoose tries to be smart and puts the collection name as the name of model's pluralize (lib/npm source code reference and all the relevant rules are defined in this file). In your case it might have created a collection named contactlists
Although there is options for you to explicitly name your collection when creating a model by passing it as the third parameter to model (the way you did it) :
var ContactSchema = new Schema({ name : String /* , ..... */ },{collection : 'contactlist'});
This behavior is clearly documented in mongoose model API reference:
When no collection argument is passed, Mongoose produces a collection name by passing the model name to the utils.toCollectionName method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option.

I resloved my problem. We have to map us with collection by
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ContactSchema = new Schema({
name : String,
email: String,
number : String
},{collection : 'contactlist'});
I worked!

Related

FindOne by index in mongoose

I have a mongoose collection that store specific data. and I have an iduser. that's name : var members = new Schema({iduser : {type : String}}).
var member = new members({iduser : req.session.user._id})
by the way I have more than one member with the same iduser. and I wanna to find them by index. member.findOne({iduser})[0].
I use nodejs for implementation.
Every MongoDb Documents have a ObjectId like "612753311aafd14844ec4933"
so You Can find same IdUser with Object Id
member.findOne({_id : "OBJECT_ID", idUser :req.session.user._id })

Populate reference object which is also a reference object mongoose

I have a schema called Message, defined likewise:
const messageSchema = new mongoose.Schema({
name : {type : String}
});
module.exports('Message',messageSchema);
I have another schema called Topic, which uses 'Message' as a reference object.
const topicSchema = new mongoose.Schema({
topics : { type : mongoose.Schema.Types.ObjectId , ref : 'Message' }
});
module.exports('Topic',topicSchema);
I have a schema called Thread, which uses an array of 'Topic' object references.
const threadSchema = new mongoose.Schema({
thread : [{ type : mongoose.Schema.Types.ObjectId , ref : 'Topic' }],
name : {type : String}
});
module.exports('Thread',threadSchema);
How to access all the 'Message' elements if we have a 'Thread' document with us?
I tried doing the following:
Thread.findOne({name : 'Climate'}).populate('thread').populate('topics').exec(function(err,data){})
but I am getting errors since thread population has an array. Please help in correctly dereferencing the message object.
After further investigations, I was able to solve the problem. An easy solution not involving nested exec statements is described.
const myThread = await Thread.find({name : "Climate"}).populate('thread');
//This populates the 'thread' component of the Thread model, which is essentially an array of 'Topic' elements.
Since we have populated the 'thread' field as an array, we can iterate through each member of that field, populating the 'topic' field present with the base 'message' model.
const myTopic = myThread.thread;
for(let i = 0; i < myTopic.length ; i++)
{
myCurrentTopic = myTopic[i];
var myTopicPopulated = await Topic.find({_id : myCurrentTopic._id}).populate('topic');
//Do further processing
}
This is a simple way to handle such cases, without resorting to usage of the path proxy.

push all element of array in subdocument while saving document

I want to push elements of array to create subdocument,
my schema
var chatGroup = new Schema({
name : {
type : String,
default : null
},
members: {
type : [subSchemaForMember]
},
}, { collection: 'chatGroup' });
var subSchemaForMember = new Schema({
user_id : {type : Schema.Types.ObjectId , ref : 'user'}},{_id : false});
my query to save document is
var chatGroup = new ChatGroup({
name : req.body.name,
image : req.body.image,
created_by : req.body.celebrity_id,
$pushAll : {'members' : req.body.members}
})
where req.body.memebers = ['someid','someid','someid']
Please help I want to do it without any loop
I don't see you actually saving the document, only calling new on the constructor. You need to explicitly call save. on the object after you construct it. For the documentation on creating documents, see here: http://mongoosejs.com/docs/models.html.
Also, the use of $pushAll only applies when you have an object already in mongodb, which has existing values, and you want to retain those values and push additional values onto the array (so in your example you can simply assign the array to members).
Also of note is that the current mongoose documentation indicates that $pushAll is deprecated and you should be using $push together with $each, but the same rules apply, see here:
https://docs.mongodb.com/manual/reference/operator/update/push/#append-multiple-values-to-an-array

Mongoose findOne embedded document by _id

I am trying to push menus to the embedded document. But I am getting not defined findOne in restaurant. I just want to push some documents into the restaurant's menu categories. As you can see in the schema:
var RestaurantSchema = new mongoose.Schema({
contactTelphone : String,
address : String,
branchID : String,
email : String,
restaurantName : String,
userID : String,
menuCategory : [MenuCategorySchema]
});
var MenuCategorySchema = new mongoose.Schema({
menuCategory : String,
menuCategoryAlt : String,
sequence : Number,
menus : [MenuSchema],
restaurantInfo : { type: Schema.Types.ObjectId, ref: 'Restaurant' },
});
var MenuSchema = new mongoose.Schema({
foodName : String,
foodNameAlt : String,
picName : String,
price : String,
rating : Number,
menuSequence : Number,
category : { type: Schema.Types.ObjectId, ref: 'MenuCategory' },
});
exports.menuForMenuCategory = function(newData, callback)
{
console.log(newData);
var menuCategoryId = newData.menuCategoryId;
var restaurantId = newData.restaurantId;
var newMenu = new Menu({
foodName : newData.foodName,
foodNameAlt : newData.foodNameAlt,
picName : newData.picName,
price : newData.price,
cookingCategory : newCookingCategory,
dishSpecial : newDishSpeical
});
Restaurant.findOne( {'_id' : restaurantId }, function(err, restaurant){
if (!err) {
//Is it how to do this? It says "findOne not defined"
restaurant.findOne( "_id" : menuCategoryId, function(err, category){
category.push(newMenu);
});
}
});
}
Subdocuments have an .id() method so you can do this:
myModel.findById(myDocumentId, function (err, myDocument) {
var subDocument = myDocument.mySubdocuments.id(mySubDocumentId);
});
See http://mongoosejs.com/docs/subdocs.html for reference.
restaurant is just an object containing the result to your query. It does not have a findOne method, only Restaurant does.
Since, MenuCategory is just a sub-document of Restaurant, this will come pre-populated whenever you retrieve a restaurant. E.g.
Restaurant.findById(restaurantId, function(err, restaurant){
console.log(restaurant.menuCategory);
// Will show your array of Menu Categories
// No further queries required
});
Adding a new Menu Category is a matter of pushing a new MenuCategory instance to the menuCategory array and saving the restaurant. This means the new menu category is saved with the restaurant and not in a separate collection. For example:
Restaurant.findById(restaurantId, function(err, restaurant){
// I'm assuming your Menu Category model is just MenuCategory
var anotherMenuCategory = new MenuCategory({
menuCategory: "The name",
menuCategoryAlt: "Alternative name",
sequence: 42,
menus: []
});
restaurant.menuCategory.push(anotherMenuCategory);
restaurant.save(); // This will save the new Menu Category in your restaurant
});
Saving a menu to a menu category follows the same procedure since, according to your schema, Menus are embedded sub-documents within each MenuCategory. But note that you need to save the restaurant as its the restaurant collection that is storing all your menus and menu categories as sub-documents
Having answered your question (I hope) I should also point out your schema design should be rethought. Having sub-documents nested within sub-documents is arguably not a good idea. I think I can see where you're coming from - you're trying to implement a SQL-like many-to-one association within your schemas. But this isn't necessary with NoSQL databases - the thinking is somewhat different. Here are some links to some SO questions about efficient schema design with NoSQL databases:
MongoDB Schema Design - Many small documents or fewer large
documents?
How should I implement this schema in MongoDB?
MongoDB relationships: embed or reference?

Mongoose embedded documents / DocumentsArrays id

In the Mongoose documentation at the following address:
http://mongoosejs.com/docs/embedded-documents.html
There is a statement:
DocumentArrays have an special method id that filters your embedded
documents by their _id property (each embedded document gets one):
Consider the following snippet:
post.comments.id(my_id).remove();
post.save(function (err) {
// embedded comment with id `my_id` removed!
});
I've looked at the data and there are no _ids for the embedded documents as would appear to be confirmed by this post:
How to return the last push() embedded document
My question is:
Is the documentation correct? If so then how do I find out what 'my_id' is (in the example) to do a '.id(my_id)' in the first place?
If the documentation is incorrect is it safe to use the index as an id within the document array or should I generate a unique Id manually (as per the mentioned post).
Instead of doing push() with a json object like this (the way the mongoose docs suggest):
// create a comment
post.comments.push({ title: 'My comment' });
You should create an actual instance of your embedded object and push() that instead. Then you can grab the _id field from it directly, because mongoose sets it when the object is instantiated. Here's a full example:
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var ObjectId = Schema.ObjectId
mongoose.connect('mongodb://localhost/testjs');
var Comment = new Schema({
title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
, comments : [Comment]
, meta : {
votes : Number
, favs : Number
}
});
mongoose.model('Comment', Comment);
mongoose.model('BlogPost', BlogPost);
var BlogPost = mongoose.model('BlogPost');
var CommentModel = mongoose.model('Comment')
var post = new BlogPost();
// create a comment
var mycomment = new CommentModel();
mycomment.title = "blah"
console.log(mycomment._id) // <<<< This is what you're looking for
post.comments.push(mycomment);
post.save(function (err) {
if (!err) console.log('Success!');
})

Resources