I'm working on a job tracker app.
User creates an account, saving the user in a mongodb collection.
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
const JobSchema = new mongoose.Schema({
position: {
type: String,
required: true
},
company: {
type: String,
required: true
},
status: {
type: String,
default: "applied"
},
date: {
type: Date,
default: Date.now
}
});
When a user adds a job, how would you store (.post) and retrieve (.get) that data to correspond to that specific user only?
Is there a way to save the users "_id" to the jobs added, and searchById to get the jobs?
It depends what exactly you want to achieve meaning what type of relationships your models will have. Lets say your users will have multiple jobs the best approach would be to store an array of ObjectIds. The refoption tells mongoose which collections to search during population of the array
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
jobs: [{type:Schema.Types.ObjecId,ref: 'Job'}]
});
and then when you query the database you chain populate('jobs') after the query.
You can read more on the subject here
For example,
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('User', UserSchema);
async function updateUser() {
let user = await User.findOne({"name": "a-unique-user-name-in-the-db"})
let userId = user._id
let newEmail = "asdf#asdf.com"
let updated = await User.updateOne(
{ "_id": userId },
{
$set: {
"email": newEmail,
}
}
)
if (updated) {
console.log("updated")
}
}
updateUser();
Related
in my resolvers I have a method to find user likes with
async function userBookmarks(args, context) {
const user = checkAuth(context);
const posts = await Post.find({likes: {userId: user.id}})
return posts; }
But GraphQL returns an empty array.
For reference, the Post model is
likes: [
{
userId: String,
createdAt: String
}],
I came across a similar problem and fixed it by defining the MongoDB Collection name in the bottom of my MongoDB Schema.
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
location: {
type: String,
required: false
}
}, { collection : 'Users' });
EDIT:
Use $elemMatch to query several fields.
const posts = await User.find({likes: {$elemMatch: {userId: user.id}}})
I can't access to _id of any mongoose.model object. I know there are a lot of similar answers but none of it solved my problem. I am using mongoose and TypeScript.
I've existing collection which contains data with existing Mixed _id:
{
_id: 10,
name: "someString",
email: "someString",
}
...
I've Schema and interface:
const UserModel: Schema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
});
export interface IUser extends Document {
name: string;
email: string;
}
export default mongoose.model<IUser>('User', UserModel);
and I try to select some user:
UserModel.findOne({email:data.email}).then((user)=>{
console.log(user);
// I get everything without _id
// { name: "someString", email: "someString" }
console.log(user.id);
// null
});
Another attempt
I've also tried to set _id to false in options:
const UserModel: Schema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
}, { _id: false });
and I tried to select some user:
UserModel.findOne({email:data.email}).then((user)=>{
console.log(user);
// I get everything with _id
// { _id: 10, name: "someString", email: "someString" }
console.log(user.id, user._id);
// but it is not accessible
// null, undefined
});
Note
If I create document record through mongoose it creates _id as ObjectId() and it is selectable.
Mongoose expects an ObjectID for _id
Add your custom type to the schema
const UserModel: Schema = new Schema({
_id: { type: mongoose.Schema.Types.Mixed, required: true },
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
});
The _id index can't be modified so don't worry about adding index options.
It's usually best to leave Mongo to use it's ObjectID.
How to define a schema that works with React and Graphql promise based.
const Cat = mongoose.model('Cat', { name: String });
You can define your schema like this:
const userSchema = new mongoose.Schema(
{
__id: mongoose.Schema.Types.ObjectId,
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String
}
},
{
timestamps: true
}
)
I have a rooms model. Within it is an array of User's which has its own model.
Each user has a bunch of different attributes, some of them being boolean. Knowing the ID of the specific room and the specific user, I am attempting to change the boolean value within a specific User element within the sub array like this:
Room.findOne({_id: roomId, "users" : user}, { "$set" : { mutedAudio : false}})
.then(doc => {
console.log("Unmuted audio");
res.json(doc)
io.in(roomId).emit('userchange');
})
.catch(err => {
console.log(err);
})
(I'm using a user model instead of a user ID for seeking the user within the sub array. Could not get ID to work but can fetch object by comparing it to itself entirely.)
I get the error:
MongoError: Unsupported projection option: $set: { mutedAudio: true }
Anyone know the answer to this?
Thank you.
EDIT:
const RoomSchema = new Schema({
owner: {
id: {
type: String
},
username: {
type: String
}
},
roomname: {
type: String,
required: true
},
category: {
type: String,
required: true
},
password: {
type: String,
required: false
},
users: [UserSchema],
messages: [{
username: {
type: String
},
message: {
type: String
},
time: {
type: String
}
}],
date: {
type: Date,
default: Date.now
}
});
const UserSchema = new Schema({
id: {
type: String
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
},
micEnabled: {
type: Boolean,
default: false
},
mutedAudio: {
type: Boolean,
default: true
}
});
Model.findOne() takes 4 parameters, the second being "optional fields to return", that's why you're getting the error, mongoose is trying to select fields to return according to $set: { mutedAudio: true } which is being passed as a second parameter (therefore considered to be a projection option).
Use Model.findOneAndUpdate() which takes an update object as a second parameter, along with the positional operator $.
Room.findOneAndUpdate(
{ "_id": roomId, "users._id": userID },{ "$set": { "users.$.mutedAudio": false } } )
.then(doc => {
console.log("Unmuted audio");
res.json(doc)
io.in(roomId).emit('userchange');
})
.catch(err => {
console.log(err);
})
Original answer by #Neil Lunn in Mongoose find/update subdocument
I am trying to associate various login methods with the same User model in mongo.
const UserSchema = new Schema({
email: String
isVerified: { default: false, type; Boolean }
accounts: {
ref: 'Account',
type: Schema.Types.ObjectId
}
})
const AccountSchema = new Schema({
facebook: {
ref: 'FacebookAccount',
type: Schema.Types.?
},
local: {
ref: 'LocalAccount',
type: Schema.Types.?
},
twitter: {
ref: 'TwitterAccount',
type: Schema.Types.?
},
})
const LocalAccount = new Schema({
email: String,
name: String,
phone: String,
password: String,
_user: {
ref: 'User',
type: Schema.Types.ObjectId
}
})
What I would like to get the data coming back to me looking like would be:
{
_id: '12345789',
email: 'turdFerguson#gmail.com',
accounts: {
facebook: { ... }
local: { ... }
}
}
I'm really unsure about these associations though hence Schema.Types.? on the individual accounts. Also unsure if I should be using embedded vs object reference and where is appropriate. I'm going in circles trying to get the associations to match up.
I suggest you keep it simple with embedded.
Here is a quick suggestion:
const UserSchema = new Schema({
isVerified: {
default: false,
type: Boolean
},
accounts: {
local: {
email: String,
name: String,
phone: String,
password: String
},
facebook: {
// fields related to Facebook
},
twitter: {
// fields related to Twitter
}
}
})
I removed email as it seems redundant to have it since you already have accounts.local.email