Can't find a document from MongoDB by ref id - node.js

I have a member in my application like so
const member = new Schema({
name: {
type: String,
required: false,
},
organization: {
type: Schema.Types.ObjectId,
ref: 'Organization',
required: true,
},
});
I struggle to find a member by organization id. Even if I first find a member by id using the following query
const member1 = await Member.findById(id).populate('organization')
and then try to find the same member using his organization id
const member2 = await Member.findOne({organization: member1.organization});
member2 comes back as null.
What am I missing? I really can't see why the member2 is null here. member1 organization is also not null. Everything I find about mongodb says that my approach should work, where am I going wrong here?
Solved:
The error occured while I was running tests. My testdata was inserted in the database like
{
_id: Types.ObjectId('5acdda00ad63c400142c22ec'),
email: 'email',
password: 'hash',
organization: '5ce474e00000000000000000',
},
And shouldve been
{
_id: Types.ObjectId('5acdda00ad63c400142c22ec'),
email: 'email',
password: 'hash',
organization: Types.ObjectId('5ce474e00000000000000000'),
},

Related

Mongoose Duplicate Key Found Error while unique is false

Okay so, basically whenever I try to create a new user mongoose throws the Error, that a duplicate key has been found:
"E11000 duplicate key error collection: test.users index: username_1 dup key: { : \"user1\" }"
I am not sure why the username would throw a duplicate key error, when I have it set to unique: false (to see if this would fix it).
This is the Schema for the users,
const UserSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
username: { type: String, unique: false },
tag: { type: String, unique: false },
email: { type: String, unique: false },
password: {type: String, unique: false },
});
And this is how I am currently saving the user
const u1 = new UserModel({
_id: mongoose.Types.ObjectId(),
username: 'one',
tag: '1',
email: 'one#hi.com',
password: '123',
})
const u2 = new UserModel({
_id: mongoose.Types.ObjectId(),
username: 'one',
tag: '2',
email: 'one.2#hi.com',
password: '123',
})
await u1.save();
console.log('Saved User 1')
await u2.save();
console.log('Saved both users');
It does save the u1 but, it throws the error for saving u2
After reading around on stackoverflow a bit, I read something about a null key, but since I manually set the username(etc), that should not be the issue, should it?
Any idea what could be causing this?
Never mind, apparently, I can't just change a Schema and expect it to work right away. I was using the same MongoDB database and collection names, and the Unique factor carried over from a previous project. Had to Drop the 'Users' Collection. Works like a charm now
( I can accept my own answer, as the post answer in two days )
For any of you that have the same problem, don't forget to Backup and Drop any old Collections, if you are using the same database and changing the Schema

Trouble with object selection in Mongoose schema

Currently building an app whereby the user can log in either locally or via google (will be expanded to other social sites). I'm using an enum array to hold the possible login methods. My user schema looks as follows:
const userSchema = new Schema({
method :{
type: String,
enum: ['local', 'google', 'twitter'],
required: true
},
local: {
email: String,
username: String,
password: String,
projects: [
{
projectName: String,
sessionLength: Number,
timestamp: Date
}
]
},
google: {
googleId: String,
email: String,
username: String,
projects: [
{
projectName: String,
sessionLength: Number,
timestamp: Date
}
]
}
});
const User = mongoose.model('user', userSchema);
module.exports = User;
The following code is used to create the new user and save to the database after authentication by Google.
let newUser = new User({
method: 'google',
google: {
googleId: profile.id,
email: profile.emails[0].value,
username: profile.name.givenName
}
});
My problem is that newUser contains, as well as the correct google object, a 'local' object with a projects array. Below is how the newUser looks. I dont want it to include the local object. It also only seems to only appear if the projects property is an array, works as expected when projects is set to be a string. What am I doing wrong?
{ method: 'google',
_id: 5a32aaa4c665b062df9c0d00,
google:
{ googleId: 'randomgoogleId',
email: 'name#gmail.com',
username: 'name',
projects: [] },
local: { projects: [] } }

Mongoose, populate where an ID is specific to a project reference

I m trying to populate a mongoose model where I only want the returned items to be the ones that are matched with an ID.
Edit update: In the User model below, I need to first find the correct user by id, then for the task property, I need to populate it where the projectID matches req.params.ID. How can I only populate the tasks where the projectID matches the req.params.ID. I have included my full User model as well as the Task model
//User Schema
var UserSchema = new Schema({
name: {
type: String,
trim: true,
required: "First Name is Required"
},
username: {
type: String,
trim: true,
required: "Username is Required"
},
skills: {
type: String,
trim : true
},
avatar: {
type: String
},
SQLid: {
type: Number
},
userCreated: {
type: Date,
default: Date.now
},
lastUpdated: {
type: Date
},
adminTeams: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
team: [{
type: Schema.Types.ObjectId,
ref: "Team"
}],
task: [{
projectID: {
type: String
},
theTask: {
type: Schema.Types.ObjectId,
ref: "Task"
}
}]
});
//Task Schema
var TodoSchema = new Schema({
task: {
type: String
}
});
How can I only get the task populated where the projectID is equal to a specific ID. I tried
User.findById({ "_id": req.params.id }).populate({ path: 'task', match: {projectID: req.params.pID}, select: 'theTask' })
.exec(function(err, docs){
console.log("POPULATE TASKS DOCS", docs)
But this is showing that the docs is empty.
you can use $elemMatch ,it will give you all those docs which matches your projectId and populate your task document .
So the query would be -
var query={
task:{
$elemMatch:{
projectId: req.params.id
}
}
}
User.find(query)
.populate('theTask')
.select('theTask') // use for getting selective data from document
.exec(function(){}) //your callback fuction
Hope I answer your question.
Thanks.
In your task schma you have kept the type of the task type as string and in your user schema the theTask have the refrence of the task and task its Self is just a string . Thats why it is not being populated ..
So change the task schema to (Keep it simple)-
var Task= new Schema({
name :string
});
Populate need refrence Id to get the whole document

Friend Request System with Express & MongoDB

I am trying to let users send friend requests to other users similar to that of Facebook and other social media platforms. I have started creating this functionality, but quickly got stuck since I am new to mongoDB and the whole Schema thing.
Here are the models I currently have:
// User Schema
var UserSchema = new Schema({
_id: {
type: Number
},
name: {
type: String
},
username: {
type: String,
index: true
},
password: {
type: String,
required: true
},
email: {
type: String
},
friends: [{
friendName: {
type: Schema.ObjectId,
required: true,
ref: 'User'
},
duration: {
type: Number
}
}]
});
// Friendship Schema
var FriendshipSchema = new Schema({
participants: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
requestTo: {
type: Schema.Types.ObjectId,
ref: 'User'
},
accepted: {
type: Boolean,
default: false
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
var Friendship = module.exports = mongoose.model('Friendship', FriendshipSchema);
var User = module.exports = mongoose.model('User', UserSchema);
This is as far as I have gotten. From here, I do not know how to use these schemas to establish friendships between 2 users. My ultimate goal is to have a button on a webpage that sends a friend request to the intended recipient, where they can then accept or deny the request.
Any help with this would be awesome, since I do not know what to do from here with these 2 schemas. Thanks!
We would need to take one schema only which is userSchema(as is Israel said above, you only need an array/object to list your friendship on the userSchema). But we will need to add another schema(said it friendRequestSchema).
FriendRequest schema would be:
- ID user request (int)
- ID user recipient (int)
- status (int) //let say 1= requested, 2=accepted, 3=rejected
And the controller it should be from the user A click "Friend Request" button on your user B page.
Friend Request Button will call a function let saying it "sendFriendRequest()"
If function running it would be recorded on friendRequest DB, which is will record ID of user A(as requester), ID of user B and request status.
If request status = 1 then user B will be notified and give him two option which is accepted and rejected.
User B accept or reject it
If user press button accept, then the status updated in friendRequest DB to be=> 2 (Accepted). Then, you have to call another function to add user ID A to friendship list of User B. Conversely. Then if you want to make a notification you can call it as well.
Else user B will press reject (status will be => 3) then notif it.
UserSchema
var UserSchema = new Schema({
name: String,
username: {
type: String,
index: true
},
password: {
type: String,
required: true
},
email: String,
friendship: [String] });
Then FriendRequestschema
var FriendRequestSchema = new Schema({
requester: {
type: int,
required: true
},
recipient: {
type: int,
required: true
},
status:
type: int,
required: true });
This just to let you know, how its work. More complex method about (sendrequest,block .etc) you can check this link, It's flow process for PHP, but you can easily move it to your js. Hope it help you man.
Your model can be improved, and your code can be cleaned:
First, you don't need the brackets if you only give type for the field:
var UserSchema = new Schema({
name: String,
username: {
type: String,
index: true
},
password: {
type: String,
required: true
},
email: String,
friends: [String]
});
This should be a simplified version of your schema. The _id field doesn't need to be specified because mongoose creates it automatically. If you wanna put a customized value there, just do it when you insert.
Second:
If you wanna reference other users, why not to use only a simple array that contains ids from other users. For example, if you have user A, the "friendship" of this user are user ids contained in his "friends" field.
{id:12345, username:"A", password:***, email:"a#fakemail.com", friends:[B_id,C_id,D_id]}
In that case, whenever you wanna make a list of friends of A, you can just perform a $lookup operation in mongodb and it will fill the other users information for you.
I don't think I covered all of your questions, but I hope my answer was helpful.

Get info from 2 separate Mongo documents in one mongoose query

Im using MongoDb, and I have a workspace schema with mongoose (v4.0.1):
var Workspace = new mongoose.Schema({
name: {
type: String,
required: true
},
userId: {
type: String,
required: true
},
createdOn: {
type: Date,
"default": Date.now
}
});
And a user schema:
var User = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
organisation: {
type: String,
required: true
},
location: {
type: String,
required: true
},
verifyString: {
type: String
},
verified: {
type: Boolean,
default: false
},
password: {
type: String,
required: true
},
createdOn: {
type: Date,
"default": Date.now
},
isAdmin: {
type: Boolean,
default: false
}
});
So the Workspace userId is the ObjectID from the User document.
When Im logged in as an adminstrator, I want to get all workspaces, as well as the email of the user that owns the workspace.
What Im doing is getting very messy:
Workspace.find({}).exec.then(function(workspaceObects){
var userPromise = workspaceObects.map(function(workspaceObect){
// get the user model with workspaceObect.userId here
});
// somehow combine workspaceObjects and users
});
The above doesnt work and gets extremely messy. Basically I have to loop through the workspaceObjects and go retrieve the user object from the workspace userId. But because its all promises and it becomes very complex and easy to make a mistake.
Is there a much simpler way to do this? In SQL it would require one simple join. Is my schema wrong? Can I get all workspaces and their user owners email in one Mongoose query?
var Workspace = new mongoose.Schema({
userId: {
type: String,
required: true,
ref: 'User' //add this to your schema
}
});
Workspace.find().populate('userId').exec( (err, res) => {
//you will have res with all user fields
});
http://mongoosejs.com/docs/populate.html
Mongo don't have joins but mongoose provides a very powerfull tool to help you with you have to change the model a little bit and use populate:
Mongoose population
You have to make a few changes to your models and get the info of the user model inside your workspace model.
Hope it helps

Resources