Mongoose: how to set a schema-field to be the ID? - mongodb

Given the following schema:
var UserSchema = new Schema({
, email : { type: String }
, passwordHash : { type: String }
, roles : { type: [String] }
});
I'd like email to be the key.
How can I define this?
I could do:
var UserSchema = new Schema({
, _id: { type: String }
, passwordHash : { type: String }
, roles : { type: [String] }
});
so MongoDB would recognize it as the id-field, and adapt my code to refer to _id instead of email but that doesn't feel clean to me.
Anyone?

Since you're using Mongoose, one option is to use the email string as the _id field and then add a virtual field named email that returns the _id to clean up the code that uses the email.
var userSchema = new Schema({
_id: {type: String},
passwordHash: {type: String},
roles: {type: [String]}
});
userSchema.virtual('email').get(function() {
return this._id;
});
var User = mongoose.model('User', userSchema);
User.findOne(function(err, doc) {
console.log(doc.email);
});
Note that a virtual field is not included by default when converting a Mongoose doc to a plain JS object or JSON string. To include it you have to set the virtuals: true option in the toObject() or toJSON() call:
var obj = doc.toObject({ virtuals: true });
var json = doc.toJSON({ virtuals: true });

Related

Mongoose Populate return null when the reference is put in sub-schema

I have 3 schemas
1. User
2. SignedToEvent
3. Events
The User contains information about user and has a relation to SignedToEvents. The SignedToEvents couples the user to an event.
The SignedToEvent is nested within User like this:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const SignedToEvents = new Schema({
event : { type: Schema.Types.ObjectId, ref: 'event' },
eventSignedDate: {type : Date, default : Date.now()},
isActive : Boolean
})
SignedToEvents.set('toObject', { getters: true });
SignedToEvents.set('toJSON', { getters: true });
const UserSchema = new Schema({
email: String,
password : String,
age : Number,
sex : String,
createdAt: { type: Date, default: Date.now },
signedToEvents : [SignedToEvents]
})
UserSchema.set('toObject', { getters: true });
UserSchema.set('toJSON', { getters: true });
module.exports = mongoose.model('user', UserSchema, 'users');
And the event schema looks like this
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const eventSchema = new Schema({
shortId : String,
name: String,
description : String,
organization : String
})
module.exports = mongoose.model('event', eventSchema, 'events');
In my API I have a call to the User collection:
User.findOne({_id : mongoose.Types.ObjectId(req.userId)})
.select("email")
.populate("event")
.exec()
.then(docs=>{
console.log(docs)
res.status(200).send(docs.signedToEvents)
});
Now, my hopes was to get an aggregated collection of User, SignedToEvent and Event. However thats not the case.
It only returns users id and email.
/Thanks
The solution was to point to my signedToEvent property and then use .event to reach the event model. Like this:
User.findOne({_id : mongoose.Types.ObjectId(req.userId)})
.select("email")
.populate("signedToEvents.event")
.exec()
.then(docs=>{
console.log(docs)
res.status(200).send(docs.signedToEvents)
});

deep populating in mongoose

I've got two schemas,
one for user and another one for post
in the user schema, I've got a property for latestPost which would be an ObjectId of an entry in the post schema
when I load up the user object,
I want to get the lastestPost as an object that includes the author's username from the user schema where the author is an ObjectId that'd match an _id field in the user schema.
the mongoose tutorials seem to use the syntax of
User.findOne({ _id: req.user.id})
.populate('latestPost')
.populate({ path: 'latestPost', populate: 'author'})
but it doesn't work
it's showing
{ _id: 58f54fa51febfa307d02d356,
username: 'test',
email: 'test#test',
firstName: 'test',
lastName: 'test',
__v: 0,
latestPost:
{ _id: 58f54fa51febfa307d02d357,
user: 58f54fa51febfa307d02d356,
author: 58f54fa51febfa307d02d356,
date: 2017-04-17T23:28:37.960Z,
post: 'Test',
__v: 0 } }
but I want it to show
latestPost:
{
author: {
username : something
}
}
how does one do something like this? is there something wrong with the design of the schema or the query?
var UserSchema = new Schema({
username : String,
firstName : String,
lastName : String,
email : String,
password : String,
views : Number,
latestPost : { type: Schema.Types.ObjectId, ref: 'Post' }
});
var PostSchema = new Schema({
user : { type: Schema.Types.ObjectId, ref: 'User' },
author : { type: Schema.Types.ObjectId, ref: 'User' },
date : Date,
body : String
});
var User = mongoose.model('User', UserSchema);
var Post = mongoose.model('Post', PostSchema);
User.findOne({ _id: req.user.id})
.populate('latestPost')
.populate({ path: 'latestPost', populate: 'author'})
.exec(function(err, user) {
if (err) res.json(err)
console.log(user)
})
Maybe just this.
I don't think you need .populate('latestPost') as your next .populate() should take care of populating the latestPost. Maybe that is interfering with the next one.
User.findOne({ _id: req.user.id }).populate({
path: 'latestPost',
model: 'Post',
populate: {
path: 'author',
model: 'User'
}
}).exec(function (err, user) {
});
You need to provide the model name also in populate function:
var UserSchema = new Schema({
username : String,
firstName : String,
lastName : String,
email : String,
password : String,
views : Number,
latestPost : { type: Schema.Types.ObjectId, ref: 'Post' }
});
var PostSchema = new Schema({
user : { type: Schema.Types.ObjectId, ref: 'User' },
author : { type: Schema.Types.ObjectId, ref: 'User' },
date : Date,
body : String
});
var User = mongoose.model('User', UserSchema);
var Post = mongoose.model('Post', PostSchema);
User.findOne({ _id: req.user.id})
.populate('latestPost')
.populate({
model: 'Post',
path: 'latestPost',
select: 'author -_id'
})
.exec(function(err, user) {
if (err) res.json(err)
console.log(user)
})

Mongoose Populate a field

I have two mongoose schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var itemSchema = new Schema({
name: {type: String, required: true, max: 25, trim: true},
price: {type: Number, required: true, trim: true, default: 0},
tax: {
type: Schema.Types.ObjectId,
ref: "Store"
}
});
module.exports = mongoose.model('Item', itemSchema);
The second Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var storeSchema = new Schema({
name: {type: String, required: true, trim: true},
taxes: [
{
name: String,
rate: Number
}
]
});
module.exports = mongoose.model('Store', storeSchema);
What I want to do is populate the itemSchema tax object with the storeSchema taxes array of object. every time I pushed a new tax object to the taxes array mongoose created an ObjectId. I stored that ObjectId in my itemSchema Tax. I want to use that _id to retrieve the store taxes that matches the itemSchema _id.
I have tried this so far, but I get no in the tax attribute.
Item.find().populate("tax", "taxes").exec(function (err, docs) {
if (err) return console.error(err);
console.log(items);
});
Try this query
Item.find().populate({
path: 'tax',
select: 'taxes'
}).exec(function (err, docs) {
if (err) {
console.error(err);
} else {
console.log(docs);
}
});
Item.find().populate(path:"tax", model: )
Mention your item model file name... don't use "" or '' for the file name, simply add the file name.
Use Item.find().populate("Store", "taxes") instead of Item.find().populate("tax", "taxes").

How can I restructure my database?

I have a collection with embedded documents. This worked fine when updating a document within a document, but when I had to update a document within a document within a document problems arose. To make this work I would need to use a double '$' and this is not possible.
This works:
{$push: {
"progress.$.exercise":{
"exercise":exercise
}
}
This is where the problem comes in:
{$push: {
"progress.$.exercise.$.workout":{
"_set":_set,
"reps":reps,
"weight":weight
}
}
Since dobbel $ can't be done and there seems to be no way (that I can find) to do it with elemMatch. I can only come to the conclusion that the way I have structured my Database is wrong....
Here are my Schemas:
var Workout = new mongoose.Schema({
_set : {
type: String
},
reps: {
type: String
},
weight: {
type: String
}
});
var Exercise = new mongoose.Schema({
exerciseName : {
type: String
},
workout : [Workout]
});
var Progress = new mongoose.Schema({
date : {
type: String
},
name : {
type: String
},
exercise : [Exercise]
});
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
progress : [Progress]
});
var User = module.exports = mongoose.model('User', UserSchema);
It seems I need to restructure my database, if so how should I do this?
Do I need to make more collections?
I'm used to relational databases and if I where to make collections out of all of them it would start to look like that.

How can I store data other than ObjectId using Mongoose populate?

Taking the example from here
http://mongoosejs.com/docs/populate.html
If I try to tweak it so that 'fans' also contains a rating
var db = require('houselib/db');
var Schema = db.Schema;
var mongoose = db.mongoose;
var PersonSchema = new Schema({
name : String
, age : Number
, stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});
var StorySchema = new Schema({
_creator : { type: Schema.ObjectId, ref: 'Person' }
, title : String
, fans : [{ type: Schema.ObjectId, ref: 'Person', rating: Number}]
});
var Story = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);
var aaron = new Person({ name: 'Aaron', age: 100 });
aaron.save(function (err) {
if (err) throw err;
var story1 = new Story({
title: "A man who cooked Nintendo"
, _creator: aaron._id
, fans: [{type: aaron._id, rating: 4}]
});
story1.save(function (err) {
if (err) throw err;
Story
.find({ _creator: aaron._id })
.populate('_creator') // <-- not really necessary
.run(function (err, stories) {
if (err) throw err;
console.log('The stories JSON is an array: ', stories);
})
});
})
I get the following error
CastError: Cast to undefined failed for value "[object Object]"
The documentation says that manual linking is preferred over DBRef
http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-SimpleDirect%2FManualLinking
story.fans is an array of objectids. objectids do cannot have ratings. You need to add the rating to the Person schema instead of the story schema.
var PersonSchema = new Schema({
name : String
, age : Number
, rating: Number
, stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});