i have such schema of sities in mongoDB
const CitiesSchema = new Schema({
name:{ type:String }
id:Object.id
});
and have such user schema
const UserSchema = new Schema({
name: { type:String, default:'' },
surname: { type:String, default:'' },
foreName: { type:String, default:'' },
email: { type:String, default:'', unique:true },
password: { type:String, default:'' },
phone: { type:String, default:'' },
role: { type:String, default:'' },
profileImg: { type:String, default:'/images/profile.png' },
createdAt: { type:Date, default:Date.now },
city: { type: Schema.Types.ObjectId, ref: 'Story' }
}, { strict: false });
how can i get City name together with user like this :
{
name:'xxxxx',
surname:'xxxxx',
city:'xxxxx' // not Object id, but name
......
}
thanks a lot !!!!
You can use mongoose population to replace the city key in the result of your query with an object in your cities collection instead of a reference. So if you write your user query like this:
User
.findOne({ name: 'Jane' })
.populate('city')
.exec(function (err, user) {
if (err) return handleError(err);
console.log('The user lives in %s', user.city.name);
// prints "The user's lives in Amsterdam"
});
You'll get the city's name in user.city.name.
Related
I wonder how can i push an item into an array contained in a Express.js Scheme.
Here is the scheme i am trying to push items into:
const mongoose = require("mongoose") ;
const Post = new mongoose.Schema({
username: {type:String, required:true},
password: {type:String, required:true},
passwordHash: {type:String, required:true},
userOrders: [{orderId: String, orderItem:String}]
}, {
collection: 'users-data'
})
module.exports = mongoose.model("PostAccount", Post)
And my attempt to do it:
userForm.findOneAndUpdate(
{username : usernameDB },
{ $push:{userOrders :{orderId: id, orderItem: item}} },
function (error, success) {
if (error) {
console.log(error);
} else {
console.log(success);
}
});
Also here you can see the output i get:
{
_id: new ObjectId("62c73f91b853f687b507b069"),
username: 'admin3',
password: 'root',
passwordHash: '$2b$10$IEausr.hQzcRcFxhSOPAN.WyNY6gBHWEOr8db7Js3/iitcAC34ple', userOrders: [
{
orderId: null,
orderItem: null,
_id: new ObjectId("62c73f91b853f687b507b06a")
}
],
__v: 0
}
Why does virtual in a nested populate return null?
I have a Post schema and a User schema like this:
Post Schema:
const PostSchema = new mongoose.Schema({
_author_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
privacy: {
type: String,
default: 'public'
},
...
}, { timestamps: true, toJSON: { virtuals: true }, toObject: { getters: true, virtuals: true } });
PostSchema.virtual('author', {
ref: 'User',
localField: '_author_id',
foreignField: '_id',
justOne: true
});
module.exports = mongoose.model('Post', PostSchema);
User Schema
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
minlength: 12,
unique: true,
validate: {
validator:
(email) => {
const regex = /^\w+([.-]?\w+)*#\w+([.-]?\w+)*(\.\w{2,3})+$/;
return regex.test(email);
},
message: '{VALUE} is invalid.'
}
},
password: {
type: String,
required: true
},
username: {
type: String,
unique: true,
required: true
}
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}],
...
}, { timestamps: true, toJSON: { virtuals: true }, toObject: { getters: true, virtuals: true } });
module.exports = mongoose.model('User', UserSchema);
And when I fetch the user to DB:
const user = await User
.findOne({ username })
.populate({
path: 'posts',
model: 'Post',
select: 'description name photos comments createdAt',
options: {
limit: 3,
sort: { createdAt: -1 },
},
populate: {
path: 'author', //virtual <------- returns null but '_author_id' is fine
model: 'User',
select: 'username fullname profilePicture'
}
})
.sort('-createdAt');
Sample returned document
{
...
"posts": [
{
"photos": [],
"comments": [
"5fe96ec48564ce31dcebe669",
"5fe97c43f4169834a48b3851",
"5fe97c726ccf4633006fbeaa"
],
"description": "Gago ka ba hahahaha",
"_id": "5fe96d84178485086090faa9",
"createdAt": "2020-12-28T05:30:44.157Z",
"author": null, // <-----
"id": "5fe96d84178485086090faa9"
}
]
}
Did I miss something? My author virtual works fine in a non-nested populate.
I think you need to add author in the outer populate select.
const user = await User.findOne({ username })
.populate({
path: 'posts',
select: 'description name photos comments createdAt author', // <------- try adding author here
options: {
limit: 3,
sort: { createdAt: -1 },
},
populate: {
path: 'author',
select: 'username fullname profilePicture',
},
})
.sort('-createdAt');
Also, you shouldn't have to add the model in the populate since it already knows which model from the schema.
I am trying to obtain data from mongodb. This is the scenario. Each user has a following property(array) that takes an array of users id.
The user model is as below
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
followers: [{ type: mongoose.Types.ObjectId, ref: "user" }],
following: [{ type: mongoose.Types.ObjectId, ref: "user" }],
});
in simple terms. I need to use two conditions where postedBy: { $in: req.user.following }, or postedBy:req.user._id
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
likes: [{ type: mongoose.Schema.ObjectId, ref: "user" }],
comments: [
{
text: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "user" },
},
],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
});
I have not figured out the second condition to add in the code below.
router.get("/getSubPost", requireLogin, async (req, res) => {
try {
const result = await Post.find({
postedBy: { $in: req.user.following },
})
.populate("postedBy", "-password")
.populate("comments.postedBy", "_id name");
res.json({ result });
} catch (error) {
console.log(error);
}
});
all.
I am writing a MEAN stack application, using Mongoose (4.0.6) with Node/Express to interface with MongoDB, and I am running into difficulty populating saved documents when I later save new documents that the existing document should have a reference to. Specifically, in the app I have a user create an instance of a company before creating their admin account for that company, so when the user registers him/herself as an admin, I'd like the company document to populate its users array with the new user.
Here are my schemas for company and user:
User.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var userSchema = new Schema({
first_name: { type: String, required: '{PATH} is required!' },
last_name: { type: String, required: '{PATH} is required!' },
username: { type: String, required: '{PATH} is required!', lowercase: true, unique: true },
password: { type: String, required: '{PATH} is required!' },
roles: { type: [String] },
company: { type: ObjectId, ref: 'Company', required: true },
db_permissions: [{ type: ObjectId, ref: 'DataConnection' }],
created_by: { type: ObjectId, ref: 'User' },
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
};
Company.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var companySchema = new Schema({
name: { type: String, uppercase: true, required: '{PATH} is required!', unique: true },
industry: { type: String, required: '{PATH} is required!' },
phone: { type: String, required: '{PATH} is required!' },
address_line_1: { type: String, uppercase: true, required: '{PATH} is required!' },
address_line_2: { type: String, uppercase: true },
city: { type: String, uppercase: true, required: '{PATH} is required!' },
state_prov: { type: String, uppercase: true, required: '{PATH} is required!' },
postal_code: { type: String, required: '{PATH} is required!' },
country: { type: String, required: '{PATH} is required!' },
logo_url: String,
users: [{ type: ObjectId, ref: 'User' }],
data_connections: [{ type: ObjectId, ref: 'DataConnection' }],
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var Company = mongoose.model('Company', companySchema);
module.exports = {
Company: Company
};
Here is the code in my controller:
User.create(userData, function(err, user) {
if(err) {
if(err.toString().indexOf('E11000') > -1) {
err = new Error('Duplicate email');
}
res.status(400);
return res.send({ reason:err.toString() });
}
console.log('company id: ' + user.company);
Company.findById(user.company)
.populate({path: 'users'})
.exec(function (err, company) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
res.send(user);
The company (e.g. TEST53) saves to the database correctly with an empty users array:
{
"_id": "55ae421bf469f1b97bb52d5a",
"name": "TEST53",
"industry": "Construction",
"phone": "2352626254",
"city": "GDFGD",
"country": "United States",
"address_line_1": "DSGDFGH",
"state_prov": "GF",
"postal_code": "45645",
"logo_url": "",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:07.609Z"
],
"created_at": "2015-07-21T12:59:07.597Z",
"data_connections": [],
"users": []
}
Then when I create the user, it saves correctly:
{
"_id": "55ae4238f469f1b97bb52d5b",
"username": "test53#test.com",
"password": "$2a$12$ZB6L1NCZEhLfjs99yUUNNOQEknyQmX6nP2BxBvo1uZGlvk9LlKGFu",
"company": "55ae421bf469f1b97bb52d5a",
"first_name": "Test53",
"last_name": "Admin",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:36.925Z"
],
"created_at": "2015-07-21T12:59:36.550Z",
"db_permissions": [],
"roles": [
"admin"
]
}
And I can see that the correct ObjectId prints to the console for user.company:
company id: 55ae421bf469f1b97bb52d5a
But the company's users array doesn't populate with the user's id, and the console.log inside the .exec function prints 'TEST53's users now includes '.
I have tried several ways of wiring this up, with just 'users' instead of { path: 'users' }, writing a function that pushes the user into the array, using .run instead of .exec, but so far without success.
Is there something obvious I'm missing? Thanks in advance for any suggestions!
You're not actually adding the user to the company.
Try this:
Company.findById(user.company, function (err, company) {
if (err) return handleError(err);
// Add the user to the company's list of users.
company.users.push(user);
// Need to save again.
company.save(function(err) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
});
res.send(user);
It seems to me that all you want to do is to update the Company model to add the user, as opposed to actually use the (populated) Company document as a response, so I left out an additional Company.findById(...).populate(...) call.
I want to do something like following code, but it failed.
var User = new Schema({
name: { type: String, required: true },
phone_number: { type: String, required: true },
modified: { type: Date, default: Date.now },
contacts: [{
user: { type : Schema.ObjectId, ref : 'User' }
}]
});
var UserModel = mongoose.model('User', User);
Is it able to achieve that purpose?
I think I used the wrong way to check it, actually it works.
Following is my test :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('localhost', 'contacts_test');
var User = new Schema({
name: { type: String, required: true },
phone_number: { type: String, required: true },
modified: { type: Date, default: Date.now },
contacts: [
{
user: { type: Schema.ObjectId, ref: 'User' }
}
]
});
var UserModel = mongoose.model('User', User);
mongoose.connection.on('open', function () {
var user1 = new UserModel({name: 'kos', phone_number: "003"});
user1.save(function (err) {
if (err) throw err;
var user2 = new UserModel({name: 'java', phone_number: "008"});
user2.contacts = [{user: user1._id}];
user2.save(function (err) {
UserModel.findById(user2._id)
.populate('contacts.user')
.exec(function (err, user) {
if (err) console.error(err.stack || err);
console.log('user name: ' + user.name);
console.error('contact of first result : ', user.contacts[0].user.name);
mongoose.connection.db.dropDatabase(function () {
mongoose.connection.close();
});
});
});
});
});