I have an application which generates the following JSON object/array which I want to save under my user in the database.
[ [ { _id: '5990e6d4fce2e705f8d74923',
fname: 'test',
lname: 'testerson1',
username: 'email1#gmail.com',
__v: 0,
userid: '5990e6b9fce2e705f8d74922' },
{ _id: '5990e6e6fce2e705f8d74924',
fname: 'test',
lname: 'testerson2',
username: 'email2#gmail.com',
__v: 0,
userid: '5990e6b9fce2e705f8d74922' } ],
[ { _id: '5990e6f7fce2e705f8d74925',
fname: 'test',
lname: 'testerson3',
username: 'email3#gmail.com',
__v: 0,
userid: '5990e6b9fce2e705f8d74922' },
{ _id: '5990e707fce2e705f8d74926',
fname: 'test',
lname: 'testerson4',
username: 'email4#gmail.com',
__v: 0,
userid: '5990e6b9fce2e705f8d74922' } ] ]
What I am not sure of is how to define this in my model, what I have tried is:
var UserSchema = new mongoose.Schema({
fname: String,
lname: String,
username: String,
password: String,
testers: [
[
{
type: mongoose.Schema.Types.ObjectId,
ref: "Tester"
}
]
]
});
With this approach, I always get MongooseError: Cast to ObjectId failed for value "[ { _id: '5990e6d4fce2e705f8d74923' error message...which I am thinking is because the array I am trying to save does not have an ObjectId.
I have also tried removing the type and ref from the schema and leaving just the array, this works...my data JSON object/array is saved fine, but as I am still learning Mongo/Mongoose, I would like to know how to define this properly.
Thanks!
EDIT:
router.post("/matchtesters", middleware.isLoggedIn, function(req, res) {
User.findById(req.user._id, function(err, user){
if (err) {
console.log(err);
} else {
Tester.find({ "userid": req.user._id }, function(err, beans) {
if (err) {
console.log(err);
} else {
console.log("TEST2: ", req.body);
console.log("TEST3: " + JSON.stringify(req.body));
user.testers.push(req.body);
user.save();
}
});
}
});
});
Related
I'm trying to populate my user requests.profileId but it returns only nulls.
I have the following schemas:
First Schema:
const profileSchema = new mongoose.Schema({
_id: { type: Number }, //<- _id is defined as a number which represents mobile number (easier for me to handle)
first: { type: String },
second: { type: String },
});
module.exports = mongoose.model('Profile', profileSchema, 'profiles');
Second Schema:
const userSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
requests: [
{
profileId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Profile',
},
requestTime: { type: Date, default: Date.now },
},
],
});
module.exports = mongoose.model('User', userSchema, 'users');
Here is my code:
const user = await User.findById(req.user).populate('requests.profileId');
console.log(user.requests);
Here is the output:
[
{
_id: 6201633869648e2b74c00a10,
profileId: null,
requestTime: 2022-02-07T18:21:44.722Z
},
{
_id: 6201633b69648e2b74c00a11,
profileId: null,
requestTime: 2022-02-07T18:21:47.238Z
},
{
_id: 620238f9d2b5dd3dee6c41a2,
profileId: null,
requestTime: 2022-02-08T09:33:45.176Z
},
{
_id: 620239253220343dfd7cfdd9,
profileId: null,
requestTime: 2022-02-08T09:34:29.780Z
}
]
Here is the output without populate:
[
{
_id: 6201633869648e2b74c00a10,
profileId: 393732353235303134343330, //<- typeof profileId is obeject
requestTime: 2022-02-07T18:21:44.722Z
},
{
_id: 6201633b69648e2b74c00a11,
profileId: 393732353435353333313131,
requestTime: 2022-02-07T18:21:47.238Z
},
{
_id: 620238f9d2b5dd3dee6c41a2,
profileId: 393732353435353333313131,
requestTime: 2022-02-08T09:33:45.176Z
},
{
_id: 620239253220343dfd7cfdd9,
profileId: 393732353435353333313131,
requestTime: 2022-02-08T09:34:29.780Z
}
]
Currently Profile.findById(mobileNumber) works fine.
Any ideas what went wrong?
Will greatly appreciate your assistance.
Thanks in advance :)
Try this might work let me know if it doesn't
const user = await User.findById(req.user).populate('Profile');
console.log(user.requests);
try this:
User.findById(req.user).populate({
path: 'requests',
populate: {
path: 'profileId',
model: 'Profile'
}
})
For future readers having the same issue!
I've found a solution for this issue.
I had to change the profileId type to Number in my userSchema:
const userSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
requests: [
{
profileId: {
type: Number // and NOT use type: mongoose.Schema.Types.ObjectId,
ref: 'Profile',
},
requestTime: { type: Date, default: Date.now },
},
],
});
module.exports = mongoose.model('User', userSchema, 'users');
Now it works!
I want to search for my users in DB using their first name and last name and then returning the full object of it but what I've found in another post is returning the _id and name which is concatenated firstName and lastName
This is the code I am using.
results = await StageOne.aggregate([
{ $project: { "name": { $concat: ["$firstName", " ", "$lastName"] } } },
{ $match: { "name": { $regex: searchInput, $options: 'i' } } }
]).collation(
{ locale: 'en', strength: 2 }
).limit(limit).skip(offset);
And the response looks something like this
{ _id: 5f064921a8900b73174f76a1, name: 'John Doe' }
What I want to be returned is something like this
{ _id: 5f08fc3b8f2719096146f767, firstName: 'John', lastName: 'Doe', email: 'johndoe#email.com' ... createdAt: 2020-07-10T23:39:39.310Z, updatedAt: 2020-07-10T23:39:39.310Z, __v: 0 }
Which I can do it by running it like this separately for firstName or lastName
results = await StageOne.find({ firstName: { $regex: searchInput, $options: 'i' } }).collation(
{ locale: 'en', strength: 2 }
).limit(limit).skip(offset);
I would suggest you to add $project at the end of your pipeline.
{$project: {$firstName:1, $lastName:1, $email:1, $name:1}}
As In
db.collection.aggregate([
{
$project: {
"name": {
$concat: [
"$firstName",
" ",
"$lastName"
]
},
firstName: 1,
lastName: 1,
data: 1
}
},
{
$match: {
"name": {
"$regex": "ohn",
"$options": "i"
}
}
},
{
$project: {
firstName: 1,
lastName: 1,
data: 1
}
}
])
play
You need to add part of your first project pipeline what are all the fields needs to be projected.
Another way to achieve this.
I am trying to build a search function that searches on username or full name ... it works fine but if username like this "example.name" or "example_name" it did not return in result if I searched like this "examplename" or "example name" how to solve this problem to return a matched characters even that special characters
User Schema
const mongoose = require("mongoose");
const bcrypt = require("bcrypt-node");
const uniqueValidator = require("mongoose-unique-validator");
const schemaTypes = mongoose.Schema.Types;
const userSchema = new mongoose.Schema(
{
firstName: { type: String, required: true, trim: true },
lastName: { type: String, trim: true },
fullName: {type: String, trim: true},
username: { type: String, trim: true, unique: true, lowercase: true },
email: {
type: String,
unique: true,
trim: true,
lowercase: true,
required: true
},
password: { type: String, select: false },
gender: { type: String, default: "male" },
birthDate: Number,
location: { type: [Number], index: '2d' }, // [<longitude>, <latitude>]
bio: {type: String, default: ""},
profilePhoto: {type: String, default: "default-user-profile.jpg"},
private: { type: Boolean, default: false },
favouriteUsers: [{ type: schemaTypes.ObjectId, ref: "users" }],
blockedUsers: [{ type: schemaTypes.ObjectId, ref: "users" }],
tempPassword: String,
tempToken: String,
socialId: String,
favouriteRequests: [{ type: schemaTypes.ObjectId, ref: "users" }],
requests: [{ type: schemaTypes.ObjectId, ref: "users" }],
followers: [{ type: schemaTypes.ObjectId, ref: "users" }],
following: [{ type: schemaTypes.ObjectId, ref: "users" }],
playerId: {type: [String], default: []}
},
{ timestamps: true }
);
userSchema.plugin(uniqueValidator, { message: "This {VALUE} is used" });
userSchema.index({ "$**": "text" });
userSchema.pre("save", function(next) {
const user = this;
if (!user.isModified("password")) return next();
if (user.password) {
bcrypt.hash(user.password, null, null, function(err, hashedPassword) {
if (err) {
return;
}
user.password = hashedPassword;
next();
});
}
});
userSchema.pre("save", function(next) {
const user = this;
if (!user.isModified("firstName") && !user.isModified("lastName")) return
next();
if (user.firstName || user.lastName) {
user.fullName = user.firstName + " " + user.lastName;
next();
}
});
userSchema.methods.comparePassword = function(password) {
return bcrypt.compareSync(password, this.password);
};
module.exports = mongoose.model("users", userSchema);
Code
function search(keyword){
return new Promise((resolve,reject) => {
const User = require('../models/users');
let str = keyword.replace(/[`~!#$%^&*()|+\=?;:'",<>\{\}\[\]\\\/]/gi, "");
let key = new RegExp(str, "ig");
User.find({
$or: [
{ fullName: { $regex: key } },
{ username: { $regex: key } },
{ firstName: { $regex: key } },
{ lastName: { $regex: key } },
{ email: { $regex: key } }
]
}).exec(async (err, users) => {
if(err) return reject(err);
resolve(users);
})
})
}
Example 1
if keyword entered "ahmed ibrahim" or "ahmed.ibrahim" result is okay as expected
result for example 1
[
{
"_id": "5b40d19ae4fc082ca8f2ff3b",
"profilePhoto": "http://localhost/public/male-image.jpg",
"firstName": "Ahmed",
"lastName": "Ibrahim",
"username": "ahmed.ibrahim65356",
"email": "example#gmail.com",
"fullName": "Ahmed Ibrahim"
}
]
Exmaple 2 the problem
if the keyword is "ahmedibrahim"
I expected the previous result put returns nothing an empty array [] hot to solve this or any suggestion match characters even contain special characters
It won't work basically because you are searching for "ahmedibrahim" and it cannot relate with any of the fields in your document.
So for this specific scenario, what I would do is create a new field say "concatFullName" which should save as firstname+lastname, then use that field contactFullName in your find ie.
contactFullName : { $regex: key }
Try below sample for aggregate,
db.getCollection('test').aggregate({
$project: {
docs: "$$ROOT",
concatname: {
$concat: [
'$firstName',
'$lastName',
]
}
}
}, {
$match: {
concatname: {
$regex: "^ahmedIbrahim$",
$options: "i"
},
}
}, {
$group: {
_id: "$_id",
docs: {
$push: "$docs"
}
}
});
This question already has answers here:
Querying after populate in Mongoose
(6 answers)
Aggregation filter after $lookup
(1 answer)
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
I have two models, Game and User. Game model is
const GameSchema = new Schema({
date: String,
time: String,
duration: Number, // minutes
location: [{ type: Schema.Types.ObjectId, ref: 'Court' }],
players_needed: Number,
max_players: Number,
level: Number,
players_list: [{ type: Schema.Types.ObjectId, ref: 'User' }], // players_list: [{ type: String }],
players_status: [{ playerId: String, status: String }], // status -joined or evaluted
postGameEvaluation: [{ playerId: String, evaluations: { } }],
author: { type: Schema.Types.ObjectId, ref: 'User' },
});
and User model is
const UserSchema = new Schema({
email: { type: String, unique: true, lowercase: true },
password: { type: String },
handle: { type: String }, // handle: { type: String, unique: true, lowercase: true },
games: [{ type: Schema.Types.ObjectId, ref: 'Post' }], // games and status
});
And I am trying to check if a User is already in the players_list of a Game using this
if (req.body.players_list.filter((e) => { return e._id === req.user._id; }).length > 0) {
.....
However, even when the User is already in the game, the if statement fails to check it. For example, here are two instances of a Game and User object where the if statement fails. This is the Game object
{ location: [],
players_list:
[ { games: [],
_id: '5b0cb9ff4a9c6a536d075f48',
email: 'efafesfse',
password: '$2a$10$bo1q0udXhL5ZnA9PMUZX4ufR0w0tcL5TmDARqAT5RpqfXheVtK3v2',
handle: 'FSEFSEFSE',
__v: 0,
id: '5b0cb9ff4a9c6a536d075f48' },
{ games: [Array],
_id: '5b0cba164a9c6a536d075f4b',
email: 'poi',
password: '$2a$10$sk.d5npeUMz0H9aQ6TKVzOir1j54UuXtdtQPIrxbKkwzPP07ODW/y',
handle: 'POI',
__v: 0,
id: '5b0cba164a9c6a536d075f4b' },
{ games: [Array],
_id: '5b0cba164a9c6a536d075f4b',
email: 'poi',
password: '$2a$10$sk.d5npeUMz0H9aQ6TKVzOir1j54UuXtdtQPIrxbKkwzPP07ODW/y',
handle: 'POI',
__v: 0,
id: '5b0cba164a9c6a536d075f4b' },
{ games: [Array],
_id: '5b0cbcd74a9c6a536d075f4e',
email: 'bv',
password: '$2a$10$BTvyzp9EnauZkODsg5010e/OUafNmjRbmAvJ33RslHbT.qiWTY4WC',
handle: 'BV',
__v: 0,
id: '5b0cbcd74a9c6a536d075f4e' } ],
_id: '5b0cba094a9c6a536d075f49',
players_status:
[ { _id: '5b0cba094a9c6a536d075f4a',
playerId: '5b0cb9ff4a9c6a536d075f48',
status: 'Joined' } ],
postGameEvaluation: [],
date: 'VVVVV',
time: 'VVVVVVV',
duration: 4,
players_needed: 4,
max_players: 4,
level: 4,
author:
{ games: [],
_id: '5b0cb9ff4a9c6a536d075f48',
email: 'efafesfse',
password: '$2a$10$bo1q0udXhL5ZnA9PMUZX4ufR0w0tcL5TmDARqAT5RpqfXheVtK3v2',
handle: 'FSEFSEFSE',
__v: 0,
id: '5b0cb9ff4a9c6a536d075f48' },
__v: 0 }
And here is the User object that is already in the players_list of the game but the if statement fails to check for it
{ games: [ 5b0cba094a9c6a536d075f49 ],
_id: 5b0cbcd74a9c6a536d075f4e,
email: 'bv',
password: '$2a$10$BTvyzp9EnauZkODsg5010e/OUafNmjRbmAvJ33RslHbT.qiWTY4WC',
handle: 'BV',
__v: 0 }
I am writing a small application that uses javascript, node, mongoDB, and mongoose. I have two collections; users and groups where every group contains an array of users
User:{_id:{type: String, required: true} FirstName: {type: String, required: true}, ..}
Group{_id:{type: String, required: true}, users:[{user: userSchema}] }
I am writing an api unit test using Mocha and Superagent. When I insert a sample document for the group that includes a nested objects for the users, I got a validation error?
Could you please let me know what is going wrong with this example?
var userSchema =
{
_id: {
type: String,
required: true,
},
profile: {
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
}
};
var GroupSchema =
{
_id: {
type: String,
required: true
},
users:[{
user: User.userSchema
}]
};
it('can query group by id', function(done) {
var users = [
{ _id: 'az', profile: {firstName: 'a', lastName: 'z'}},
{ _id: 'bz', profile: {firstName: 'b', lastName: 'z'}},
];
User.create(users, function(error, users) {
assert.ifError(error);
Group.create({ _id: 'ab', users: [{ _id: 'az', profile: {firstName: 'a', lastName: 'z'}}, { _id: 'bz', profile: {firstName: 'b', lastName: 'z'}}] }, function(error, doc) {
assert.ifError(error);
var url = URL_ROOT + '/api/groups/id/ab';
superagent.get(url, function(error, res) {
assert.ifError(error);
var result;
assert.doesNotThrow(function() {
result = JSON.parse(res.text);
});
assert.ok(result.group);
assert.equal(result.group._id, 'ab');
done();
});
});
});
});
Error Message:
Uncaught ValidationError: ChatGroup validation failed: users.1._id: Cast to ObjectID failed for value "bz" at path "_id", users.0._id: Cast to ObjectID failed for value "az" at path "_id", users.0.user.profile.lastName: Path `user.profile.lastName` is required., users.0.user.profile.firstName: Path `user.profile.firstName` is required., users.0.user._id: Path `user._id` is required., users.1.user.profile.lastName: Path `user.profile.lastName` is required., users.1.user.profile.firstName: Path `user.profile.firstName` is
I think your GroupSchema definition is incorrect:
var GroupSchema =
{
_id: {
type: String,
required: true
},
users:[{
user: User.userSchema
}]
};
The way you're using it in the test users array should have type of User.userSchema array:
var GroupSchema =
{
_id: {
type: String,
required: true
},
users:[{
type: User.userSchema // type, not 'user'
}]
// OR just: users: [User.userSchema]
};
Otherwise, if you still need to use your original schema, then in your test you should use it this way:
var users = [
{ user: { _id: 'az', profile: {firstName: 'a', lastName: 'z'}} },
{ user: { _id: 'bz', profile: {firstName: 'b', lastName: 'z'}} },
];