I'm trying to accomplish something really easy but still manage to fail.
What I am trying to do is when I get a get request on my server I want to return all documents BUT just the specific fields populated.
My schema goes as follows
var clientSchema = new Schema({
name:{
type: String,
required: true
},
phone:{
type: String,
required: true
},
email:{
type: String,
required: true
},
address: {
type: String,
required: false
}
});
var orderDetailsSchema = new Schema({
//isn't added to frontend
confirmed:{
type: Boolean,
required: true,
default: false
},
service:{
type: String,
required: true
},
delivery:{
type: String,
required: false
},
payment:{
type: String,
required: false
},
status:{
type: String,
required: true,
default: "new order"
},
});
var orderSchema = new Schema({
reference:{
type: String,
required: true
},
orderdetails: orderDetailsSchema,
client: clientSchema,
wheelspec: [wheelSchema],
invoice:{
type: Schema.Types.ObjectId,
ref: 'Invoice'
}
});
What I want is to return only client.phone and client.email plus orderdetails.status but still retain reference field if possible
I have tried using lean() and populate() but had no luck with them. Is there anything utterly simple I am missing? Or what I am trying to achieve is not that easy?
Thanks!
You can specify the fields to return like this:
Order.findOne({'_id' : id})
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
Alternative syntax
Order.findOne({'_id' : id})
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
I've made a number of assumptions here, but you should be able to see the idea.
Simply do like this :-
Order is model name which is registered in mongoose.
Order.findById(id) // set id you have to get
. populate('client')
.select('client.phone client.email orderdetails.status reference')
.exec(function(err, order) {
//
});
You can use projection.
await Order.findById(diaryId, {phone: 1, email: 1, status: 1})
If phone:1 is set to 1, it is included, if phone:0, then it's excluded.
Related
I'm sorry if this might be a duplicate question but I'm quite having a hard time understanding Mongoose. I am working on a Node.js project that implements Mongoose and MongoDB. What I want to accomplish is to modify and save some users' data through a call from a specific endpoint.
Mongoose Schema looks like this
var UserSchema = new Schema({
isAdmin: {type: Boolean, default: false},
name: String,
surname: String,
nickname: { type: String },
email: { type: String, lowercase: true, required: true, trim: true, unique: true, dropDubs: true },
password: { type: String, required: true },
salt: { type: String },
verified: { type: Boolean, default: false },
bio: {
type: { type: String, enum: [0,1] }, // 0='Appassionato', 1='Giocatore'
birthday: String,
height: Number,
number: Number,
role: { type: String, enum: [0,1,2,3] }, // 0='Playmaker', 1='Ala', 2='Guardia', 3='Centro'
team: String,
city: String,
aboutMe: String,
},
newsletter: {type: Boolean, default: false},
lastCheckin: {type: mongoose.Schema.Types.ObjectId, ref: 'Checkin'},
follows: [{type: mongoose.Schema.Types.ObjectId, ref: 'Structure'}],
score: { type: Number, default: 0 },
profilePicture: String,
lastLogin: {type: Date},
facebook: {
id: String,
accessToken: String,
profileImage : String
}
}, {
collection: 'users',
retainKeyOrder: true,
timestamps: true,
}).plugin(mongoosePaginate);
Following is the code for when the endpoint gets interrogated
exports.updateUser = (req,res) => {
var userId = req.params.userId;
var updates = req.body;
User.findOneAndUpdate({_id: userId}, {$set: updates}, (err, saved) => {
if (!err) {
console.log("Ritorno questo: " + saved);
return res.status(202).json(saved);
} else {
return res.status(500).json(saved);
}
});
};
As far as I understood, the method findOneAndUpdate exposed by Mongoose should find the document I'm looking for and then modify it and save it. This doesn't happen though.
Through PostMan I'm sending this JSON
{"bio.aboutMe":"Hello this is just a brief description about me"}
But PostMan is responding with the non-modified object. What am I missing here?
What you need to do is to add {new:true}, it give you back the updated document.
In the documentation :
If we do need the document returned in our application there is
another, often better, option:
> Tank.findByIdAndUpdate(id, { $set: { size: 'large' }}, { new: true },
> function (err, tank) { if (err) return handleError(err);
> res.send(tank); });
This is something I don't really like as there is another option if we don't want to have the document → update
So what you need to do is :
User.findOneAndUpdate({_id: userId}, {$set: updates}, {new:true}.....
I am pushing nested JSON data to database. This is how my schema looks like,
const mongoose = require('mongoose');
// original Schema
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{type: String, required: true}
});
module.exports = mongoose.model('DataSource', dataSourceSchema);
I would like to pass the following json data to my dataSourceSchema,
{
“name”:”JdbcSourceConnector”,
"type" :"string",
“config”: {
“connector.class”:” io.confluent.connect.jdbc.JdbcSourceConnector”,
“tasks.max”:1,
“connection.url”:”<connection to connect to database along with username and password>”,
“mode”:”incrementing”,
“incrementing.column.name”:”<incrementing column name in table>”,
“topic.prefix”:”test-mysql-jdbc-”
}
}
But its not taking, gives casting error or ',' expected.
So i tried this,
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{
connector.class:{ type: String, required: true },
tasks.max:{ type: String, required: true },
connection.url:{ type: String, required: true },
mode:{ type: String, required: true },
incrementing.column.name:{ type: String, required: true },
topic.prefix:{ type: String, required: true }
}
});
this Schema is also giving me errors, ',' expected.
If i pass just a string as i have mentioned in my original schema, the data gets stored in db.
but i want to pass the nested json data, please guide me in right direction.
I also tried stringify the data , its not working.
As I see it , the error lies in defining you schema with your second schema you came close to the answer. Change you schema as follows:
const dataSourceSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: true },
type: { type: String, required: true },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
config:{
connectorClass:{ type: String, required: true },
tasksMax:{ type: String, required: true },
connectionUrl:{ type: String, required: true },
mode:{ type: String, required: true },
incrementingColumnName:{ type: String, required: true },
topicPrefix:{ type: String, required: true }
}
});
I have suggested the change as mongoose doesn't understand the dot notation in the key column of it's schema, hence you were receiving the error you have mentioned.
If you want to use the dot notation for some reason encapsulate the key in " and not in the special character as appearing in your code snippet.
P.s. - Don't forget to change the key names in your json
var buyerSchema = new Schema({
cart: [{
id: {
type: Schema.Types.ObjectId,
ref: "product"
},
number: Number
}],
personName: { type: String, required: true, trim: true },
image: { type: String, required: false, trim: true },
email: { type: String, required: true, trim: true }
})
How can i populate the Id field
buyerMdl.findByToken(buyer['token']).populate({path: 'cart', populate: {path : 'id', model : 'product'}})
this particular command is not working for me
First of all make sure your findByToken method returns an instance of find so that you can use .populate() in the chain.
The problem is that you're trying to populate a property which is not referenced. So instead of populating card and then ids in it, you should directly populate cart.ids.
This should work:
buyerMdl
.findByToken(buyer['token'])
.populate({
path: 'cart.id',
model: 'product'
});
Your id is inside card array... So you should use with dot notation to populate id
buyerMdl.findByToken(buyer['token']).populate({ path: 'cart.id' })
I'm doing a MMO Real-Time Browser game, and I'm storing data using Mongoose (MongoDB).
First of all, I'll show you the structure of my object:
var playerSchema = new Schema({
name: { type: String, required: true, trim: true, index: { unique: true } },
resources: {
wood: { type: Number, required: true, default: 500},
stone: { type: Number, required: true, default: 300},
iron: { type: Number, required: true, default: 0},
cereal: { type: Number, required: true, default: 0}
},
resourcesPerHour: {
woodPerHour: { type: Number, required: true, default: 40},
stonePerHour: { type: Number, required: true, default: 20},
ironPerHour: { type: Number, required: true, default: 0},
},
res: {type: Array, required:true, default: []},
buildings: { type: Array, required: true, default: []},
researches: { type: Array, required: true, default: []}
});
As you can see, res, buildings, and researches are arrays. I'm gonna show you one of them (they all have the same structure):
var buildingSchema = new Schema({
id: {type: String, requried: true},
name: { type: String, required: true, trim: true, index: { unique: true } },
level: { type: Number, required: true, default: 0},
scalingValue: {type: Number, required: true, default: 2},
costs: {
wood: { type: Number, required: true, default:0},
stone: { type:Number, required:true, default:0},
iron: {type:Number, required:true, default:0},
cereal: {type:Number, required:true, default:0}
}
});
OK, imagine I have a player, with all data initializated. When I try to update something, I can only update information out of that lists. Look this example:
player.findOne({name:req.session.name}, function(err, doc){
doc.resources.wood -= 200;
doc.buildings[id%100].costs.wood *= 2;
doc.save(function(err){
if(err)console.log(err);
});
}
When I look the model on database, it only stored the resources.wood, not the building[i].costs.wood. I don't know why it's failing, but all objects inside the arrays are created using a new variable, where variable is a Schema (like buildingSchema).
One more thing, I added a console.log(doc.buildings[i].costs.wood); just before the doc.save() and it's ok. So it means all the data is modified fine, but in the doc.saveit only save the 'not-in-list' data.
EDIT: console.log(err); doesn't print nothing, so it means the save function worked.
When you use the Array type in your schema (same as the Mixed type in the docs), you need to explicitly mark the field as modified or Mongoose won't save any changes you make to it.
doc.markModified('buildings');
doc.save(function(err){
if(err)console.log(err);
});
The better approach may be to declare buildings as containing an array of buildingSchema:
buildings: [buildingSchema],
That way Mongoose will be able to track the changes you make to the buildings array automatically.
https://groups.google.com/forum/#!topic/mongoose-orm/5m7ZPkhFyrc
Subdocuments that are not inside of an array are not supported by mongoose. My recommendation is to drop mongoose completely and just use direct queries to the db. You'll find the node native driver is quite easy to use.
I have defined a mongoose user schema:
var userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true},
password: { type: String, required: true},
name: {
first: { type: String, required: true, trim: true},
last: { type: String, required: true, trim: true}
},
phone: Number,
lists: [listSchema],
friends: [mongoose.Types.ObjectId],
accessToken: { type: String } // Used for Remember Me
});
var listSchema = new mongoose.Schema({
name: String,
description: String,
contents: [contentSchema],
created: {type: Date, default:Date.now}
});
var contentSchema = new mongoose.Schema({
name: String,
quantity: String,
complete: Boolean
});
exports.User = mongoose.model('User', userSchema);
the friends parameter is defined as an array of Object IDs.
So in other words, a user will have an array containing the IDs of other users. I am not sure if this is the proper notation for doing this.
I am trying to push a new Friend to the friend array of the current user:
user = req.user;
console.log("adding friend to db");
models.User.findOne({'email': req.params.email}, '_id', function(err, newFriend){
models.User.findOne({'_id': user._id}, function(err, user){
if (err) { return next(err); }
user.friends.push(newFriend);
});
});
however this gives me the following error:
TypeError: Object 531975a04179b4200064daf0 has no method 'cast'
If you want to use Mongoose populate feature, you should do:
var userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true},
password: { type: String, required: true},
name: {
first: { type: String, required: true, trim: true},
last: { type: String, required: true, trim: true}
},
phone: Number,
lists: [listSchema],
friends: [{ type : ObjectId, ref: 'User' }],
accessToken: { type: String } // Used for Remember Me
});
exports.User = mongoose.model('User', userSchema);
This way you can do this query:
var User = schemas.User;
User
.find()
.populate('friends')
.exec(...)
You'll see that each User will have an array of Users (this user's friends).
And the correct way to insert is like Gabor said:
user.friends.push(newFriend._id);
I'm new to Mongoose myself, so I'm not entirely sure this is right. However, you appear to have written:
friends: [mongoose.Types.ObjectId],
I believe the property you're looking for is actually found here:
friends: [mongoose.Schema.Types.ObjectId],
It may be that the docs have changed since you posted this question though. Apologies if that's the case. Please see the Mongoose SchemaTypes docs for more info and examples.
I would try this.
user.friends.push(newFriend._id);
or
friends: [userSchema],
but i'm not sure if this is correct.