Populate reference object which is also a reference object mongoose - node.js

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.

Related

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

How to define a model & method in mongoose midleware?

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!

How to find an object's path with attribute values in mongoose?

I want to use an object named 'task' in my mongodb database. a task can have one or more tasks as its children. I need to find a task which may lie down at any level of the hierarchy with its _id or other attributes values. How can I do that in mongoose or mongodb?
My task schema will be as follows:
var mongoose = require('mongoose');
var Project = require(./project.js);
var Resource = require(./resource.js);
var Group = require(./group.js);
var Phase = require(./phase.js);
var Objective = require(./objective.js);
var Milestone = require(./milestone.js);
var Decision_tag = require(./decision_tag.js);
var createInfo = require(./plugins/createInfo);
var taskSchema = new mongoose.Schema(
{
title :{ type : String, unique : true, required : true, trim :true},
resources :[{type : mongoose.Schema.Types.ObjectId , ref : 'Resource', required, false}],
groups :[{type : mongoose.Schema.Types.ObjectId , ref : 'Group', required, false}],
tasks :[{type : mongoose.Schema.Types.ObjectId , ref : 'Task', required, false}],
decision_tags :[{type : mongoose.Schema.Types.ObjectId , ref : 'Decision_tag' , required : false}]
});
taskSchema.plugin(createInfo);
module.exports = mongoose.model('Task' , 'taskSchema' , tasks);
With the schema defined in your code above all your tasks are stored in one collection as "top-level tasks". Your hierarchy only exists as references between those tasks, so you can just query with all the normal mongoose query functionality to find your task or subtask, e.g.:
mongoose.model('Task').find({title: 'myTitle'});
the main remaining problem is probably to find/load/display the whole hiearchy of the subtask you found. Maybe it would be better to store a reference to a task's parent task instead of storing the children. Or doing both. It really depends whether you want to optimize for write or for read. Storing the parent task allows you to easily identify a top-level task (parent is emtpy).
If you never display/load a subtask without its whole hierarchy, you could also use subdocuments instead of ObjectId-references, but then querying for subtasks will be tricky.

CastError: Cast to ObjectId failed for value "" at path "_id"

Well, I see that here are a few posts like this, but they didn't help me ...
let me describe my problem:
I have two Schema's
var A = new Schema({
someAttribut: {type: String},
b: {type: ObjectId, ref:'B'}
});
var B = new Schema({
someAttribut2: {type: Boolean, 'default': false'}
});
Now I'm in the situation that I already have a B-Object and I want to create an A-Object.
So i do it this way:
var a = new A(req.aFromClient); // {_id:null, someAttribute:'123', b:null}
//load b from Database ...
a.b = existingBFromDatabase; // {_id: 'Sb~Õ5ÙÐDâb', someAttribute2: false}
The b object is loaded from my monogDB. The debugger shows me a valid ObjectId (53627ed535d9d04416e26218 or Sb~Õ5ÙÐDâb) for my b .
But when I save my new A-Object, i get the error: 'CastError: Cast to ObjectId failed for value "" at path "_id"'
I don't understand why I get this error.
Firstly, I don't define the id in the schema, so mongoose should add it, which seems to work.
Secondly, I think that mongoose should generate a new ID when I create an a object.
do you have any proposal?
Based on the comment in the code, _id does have a value (of null). So you need to remove _id from req.aFromClient before creating your new A doc from it:
delete req.aFromClient._id;
var a = new A(req.aFromClient);
You should do:
a.b = existingBFromDatabase._id;
Because mongoose only works with the id of the already existing object.

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