Mongoose embedded documents / DocumentsArrays id - node.js

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!');
})

Related

Insert multiple document with mongoose

I made an API with express.js, and i use mongoDB for my database and mongoose as my ODM
I really confused when i want to insert multiple document to my collection in once post request.
Here my model :
const modul = require('../config/require');
const Schema = modul.mongoose.Schema;
let TeleponSchema = new Schema({
_pelanggan : {type: String},
telepon: {type: String, required: true}
});
module.exports = modul.mongoose.model('telepon', TeleponSchema, 'telepon');
and here my controller
const Telepon = require('../models/telepon.model')
exports.create = (req,res) => {
let telepon = new Telepon({
_pelanggan : req.body.pel,
telepon: req.body.telepon
});
telepon.save((err,data) => {
if(err){
res.send({message:'eror', detail: err});
}else{
res.send({message:'success', data: data})
}
});
}
Then i post my request with postman like this :
but the result in my document is :
that's the problem, the value of 'telepon' is in the same row and separated by comma instead of insert a new row and create a new _id
i want the result of my collection like this :
(example)
Any help and suggestion would be much appreciated
Thank you!
1) Per .save call you will only affect one document, check out insertMany to do multiple.
2) req.body.telepon is either an array of numbers, or is already just the comma delimited list of numbers; if it is an array the .toString will result in a comma delimited list anyways. So when you new up the Telepon it has both values in one property, which is what you see in the result.

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!

Create hashid based on mongodb '_id` attribute

I have my mongo db schema as follows:
var MyTable = mongoose.model('items', {
name: String,
keyId: String
});
I would like to store keyId as a hashid of '_id' for the item being created.
Eg.
Say, i add an item to db "Hello world", and mongodb would create some '_id' for the item while inserting.
I would like to make use of the _id so that i could use that and generate a hashid for the same item being inserted. Something like this:
var Hashids = require("hashids"),
hashids = new Hashids("this is my salt");
var id = hashids.encrypt("507f191e810c19729de860ea");
Is there a way, I could know the id before hand. Or I could let mongodb generate value for my id field based on criteria I specify.
You can use pre save middleware to perform operations on the object instance before it gets saved.
var MyTableSchema = new mongoose.Schema({
name: String,
keyId: String
});
var Hashids = require("hashids");
MyTableSchema.pre('save', function(next) {
if (!this.keyId)
this.keyId = new Hashids("this is my salt").encrypt("507f191e810c19729de860ea");
next();
});
var MyTable = mongoose.model('items', MyTableSchema);
Just a note on this. The Hashids module has an EncryptHex (or EncodeHex in v1.x), that is intended for use with mongodb ids.

find id of latest subdocument inserted in mongoose

i have a model schema as :
var A = new Schema ({
a: String,
b : [ { ba: Integer, bb: String } ]
}, { collection: 'a' } );
then
var M = mongoose.model("a", A);
var saveid = null;
var m = new M({a:"Hello"});
m.save(function(err,model){
saveid = model.id;
}); // say m get the id as "1"
then
m['b'].push({ba:235,bb:"World"});
m.save(function(err,model){
console.log(model.id); //this will print 1, that is the id of the main Document only.
//here i want to find the id of the subdocument i have just created by push
});
So my question is how to find the id of the subdocument just pushed in one field of the model.
I've been looking for this answer as well, and I'm not sure that I like accessing the last document of the array. I do have an alternative solution, however. The method m['b'].push will return an integer, 1 or 0 - I'm assuming that is based off the success of the push (in terms of validation). However, in order to get access to the subdocument, and particularly the _id of the subdocument - you should use the create method first, then push.
The code is as follows:
var subdoc = m['b'].create({ ba: 234, bb: "World" });
m['b'].push(subdoc);
console.log(subdoc._id);
m.save(function(err, model) { console.log(arguments); });
What is happening is that when you pass in the object to either the push or the create method, the Schema cast occurs immediately (including things like validation and type casting) - this means that this is the time that the ObjectId is created; not when the model is saved back to Mongo. In fact, mongo does not automatically assign _id values to subdocuments this is a mongoose feature. Mongoose create is documented here: create docs
You should also note therefore, that even though you have a subdocument _id - it is not yet in Mongo until you save it, so be weary of any DOCRef action that you might take.
The question is "a bit" old, but what I do in this kind of situation is generate the subdocument's id before inserting it.
var subDocument = {
_id: mongoose.Types.ObjectId(),
ba:235,
bb:"World"
};
m['b'].push(subDocument);
m.save(function(err,model){
// I already know the id!
console.log(subDocument._id);
});
This way, even if there are other database operations between the save and the callback, it won't affect the id already created.
Mongoose will automatically create an _id for each new sub document, but - as far as I know - doesn't return this when you save it.
So you need to get it manually. The save method will return the saved document, including the subdocs. As you're using push you know it will be the last item in the array, so you can access it from there.
Something like this should do the trick.
m['b'].push({ba:235,bb:"World"});
m.save(function(err,model){
// model.b is the array of sub documents
console.log(model.b[model.b.length-1].id);
});
If you have a separate schema for your subdocument, then you can create the new subdocument from a model before you push it on to your parent document and it will have an ID:
var bSchema = new mongoose.Schema({
ba: Integer,
bb: String
};
var a = new mongoose.Schema({
a: String,
b : [ bSchema ]
});
var bModel = mongoose.model('b', bSchema);
var subdoc = new bModel({
ba: 5,
bb: "hello"
});
console.log(subdoc._id); // Voila!
Later you can add it to your parent document:
m['b'].push(subdoc)
m.save(...

Nested models mongoose with nodejs generates duplicates

here is my code for models.js where I keep models
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var GroupSchema = new Schema({
title : String
, elements : [ElementSchema]
, author : String
});
var ElementSchema = new Schema({
date_added : Date
, text : String
, author : String
});
mongoose.model('Group', GroupSchema);
exports.Group = function(db) {return db.model('Group');};
mongoose.model('Element', ElementSchema);
exports.Element = function(db) { return db.model('Element');
};
To me it looks pretty clear, but when I do
function post_element(req, res, next) {
Group.findOne({_id: req.body.group}, function(err, group) {
new_element = new Element({author: req.body.author,
date_added: new Date()});
new_element.save();
group.elements.push(new_element);
group.save();
res.send(new_element);
return next();
})
}
I don't understand why when I go in Mongo I have two collections one called Groups with nested groups (so it looks fine) and the other collection is called Elements.
Why? Shouldn't it be called just Group ?
I don't understand, a good chap that please explain it to me?
Thanks,
g
When you execute this line:
new_element.save();
you're saving the newly created element to the Elements collection. Don't call save on the element and I think you'll get the behavior you're looking for.
Its because of the following line:
mongoose.model('Element', ElementSchema);
This registers a model in mongoose and when you register a model, it will create its own collection inside mongo. All you have to do is get rid of this line and you will see it disappear.
On another note, its much cleaner and easier to setup your files to only export one model per file using the following to export the model:
module.exports = mongoose.model('Group', GroupSchema);
Hope this helps!

Resources