mongoose: getting unknown objectId when stored string instead of objectId - mongodb

According to me when i pushed 'ABC' instead of objectId, It should show some error like
Cast to ObjectId failed for value "ABC" at path "likes".
but when i print that updated data i saw some unknown objectId in likes array
My question is, what is that unknown objectId(6a61736f6e20626f75726e65) and why it is generated
automatically
User Model
new Schema({
name: { type: String,required:true},
}, { usePushEach: true ,timestamp:true});
Feed Model
new Schema({
user: { type: Types.ObjectId, ref: 'user', required: true },
name: { type: String,default:null, trim: true },
likes: [{ type : Types.ObjectId, ref: 'user',}],
}, { usePushEach: true ,timestamp:true});
In Feed Schema likes have reference to User Schema
var data = await feed.findByIdAndUpdate(
postId,
{
$push: { likes: 'ABC' }
}
);
if(data){
var data = await feed.findById(postId);
console.log(data.likes);//["6a61736f6e20626f75726e65"]
}
OutPut:
["6a61736f6e20626f75726e65"]

Since you are pushing a String in likes which is not an ObjectId, you are getting this error.
Your schema clearly states that likes is an array of ObjectId:
likes: [{ type : Types.ObjectId, ref: 'user'}],
so you have to pass an ObjectId instead of user's name.
You have to do this:
// Whenever you are pushing value in `likes` `array`,
// you need to get the `ObjectId` of the user who liked the feed.
let userId = <userId_of_Ishwar>;
var data = await feed.findByIdAndUpdate(
postId,
{
$push: { likes: userId }
});

Related

GraphQL Mutation Updating Users Followers with Mongoose/MongodDB - $set is empty error

I have this mutation set up:
followUser: {
type: UserType,
args: {
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString)},
},
resolve(parentValue, { firebaseUid, _id, following}) {
const update = {
$set: { "following": [firebaseUid] },
$push: { "following": { firebaseUid } }
}
return UserSchema.findOneAndUpdate(
{ _id },
update,
{new: true, upsert: true}
)
}
},
I'm trying to add new followers into my graphql user's collection. My user model:
const UserSchema = new Schema(
{
firebaseUid: String,
following: [{ type: Schema.Types.ObjectId, ref: 'User' }],
followers: [{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
So at first, the user doesn't have any followers, so it won't have that field yet. When user adds someone to their friends list, thats when the field will appear in mongodb. Right now I'm getting this error:
"message": "'$set' is empty. You must specify a field like so: {$set: {<field>: ...}}",
I'm not sure if I'm doing the $set correctly.
The UserType
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString) },
followers: { type: new GraphQLList(GraphQLString) },
...
})
});
edit:
current mongodb data collection:
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
after running the update
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
following: ["fdsaduybfeaf323dfa"] // <-- this gets added
Currently mongooses validator is rejecting the update. To fix this you need the following:
You only need to $push since it will automatically create an array if the property does not exist
You should remove the extra { } around the firebaseUid in the $push because otherwise the following array will contain objects with a firebaseUid property instead of directly containing the Uid (or would if the schema validator allowed it)
Mongo ObjectIds can only be converted from strings when they are 12-byte hexadecimal, and firebaseUid is not, so the schema should be typed to String instead of ObjectId as the validator will reject the field for update otherwise.

Ensure a unique index on nested reference on a mongoose schema

What I want is that a user can like a post only once, hence I uniquely indexed the user in the likes array to ensure the same, but it isn't working and I can't find out what is wrong here .
The schema looks like this :
const mongoose = require('mongoose')
const postSchema = new mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User' // User model
},
text: {
type: String,
required: [true, 'Post must have some text']
},
likes: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}
],
comments: [
{
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
text: {
type: String,
required: [true, 'Comment must have some text']
},
addedAt: {
type: Date,
default: Date.now
}
}
],
createdAt: {
type: Date,
default: Date.now
}
})
postSchema.pre(/^find/, function(next) {
this.populate({
path: 'author',
select: 'name avatar'
}).populate({
path: 'comments.author',
select: 'name avatar'
})
next()
})
// Ensure a user can like a post only once
postSchema.index({ 'likes.user': 1 }, { unique: true })
const Post = mongoose.model('Post', postSchema)
module.exports = Post
However when I send a post request to like a post twice via the same user it
shows no error.
Here is the postman output
I have tried both the ways listed in this, but none of them worked in this case.
Mongoose Index on a field in nested document
How do I ensure a user can like a post only once from the schema itself ?
Try saving likes in this format in the database
likes:[{type:mongoose.Schema.Types.ObjectId,ref: 'User'}]
making it
likes:[ObjectId("5af03111967c60501d97781f")]
and when the post like API is hit do
{$addToSet: {likedBy: userId}}
in update query,addToSet ensures no duplicate ids are maintained in the array.

Fetch user details based on userId which is referenced field in userDetails table

Database: MongoDB
Backend: Node.js
There are two tables in the database: User and userDetails. ObjectId in User table has been used as a reference in userDetails table as userId. Now based on this userId I want to display userDetails.
I have tried to make a function and tried to test that in postman but I get null data. When I test this function in api testing tool postman, I don't get any user Details. I am not able to understand why I am not getting any data.
Here is the function:
function getUserDetailByUserId(req, res) {
userDetails.find(req.params.userId, (error, detail) => {
if (error)
res.send(error);
res.json(detail);
}).populate(userId);
}
use ObjectId
new mongoose.mongo.ObjectID(req.params.userId)
function getUserDetailByUserId(req, res) {
userDetails.findOne({userId: new mongoose.mongo.ObjectID(req.params.userId)})
.populate(userId)
.exec(function(error, detail){
if (error)res.send(error);
res.json(detail);
});
}
userDetail Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const userDetailSchema = new Schema({
dateOfBirth: {
type: Date,
required: true
},
gender: {
type: String,
required: true
},
country: {
type: String,
required: true
},
interest: {
type: String,
required: true
},
remarks: {
type: String,
},
userId: {
type: Schema.Types.ObjectId, // Referencing the Registered Users in User Model by their ObjectId reference.
ref: 'User' // Creating a relation between User and UserDetails Model through unique ObjectId.
}
});
module.exports = mongoose.model('UserDetails', userDetailSchema);

Mongo find users that are not blocked

I have a db in Mongo with users. I want to retrieve all user that are not in my blocked Array. tried to filter through the results by retrieving All documents but I wonder if that's the most efficient way. Is there a way in Mongo to find all users that are not part of an array?
Here is my User model:
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true,
unique: true
},
password: {
type: String
},
email: {
type: String,
unique: true
},
name: {
type: String
},
latitude:{
type: String
},
longitude:{
type: String
},
blocked:{
type: Array
},
friends:{
type: Array
},
photo:{
type: String
},
identity:{
type: String
},
age:{
type: String
},
herefor:{
type: String
},
conns:{
type: Number
},
status:{
type: String
}
}, { collection: 'users' });
You are probably looking for something like the following, assuming your blocked users array contains usernames and your mongoose model is called UserModel:
var blockedUsernamesArray = [];
UserModel.find({ username: { $nin: blockedUsernamesArray } }, function(err, docs) {
// Handle result
})

How to save populated Document?

Is it possible to save a populated document?
I am trying to do:
var Group = new Db['Group']();
for (var i=0; i<50; i++)
Db.Members.push({ User: { _id: "521014731e27b1b008000002"}, pseudo: 'John' });
Group.save();
Schemas
var GroupSchemaModel = {
Members: [{
User: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
updated_at: { type: Date, required: true, default: Date.now }
}]
};
I get the error
{ message: 'Cast to ObjectId failed for value "[object Object]" at path "User"',
name: 'CastError',
type: 'ObjectId',
value: { _id: '521014731e27b1b008000002' },
path: 'User' }
This:
User: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
Tells mongoose that User field will be a collection of references of type ObjectId pointing to another collection.
You, on the other hand, are trying to insert an object there:
Db.Members.push({ User: { _id: "521014731e27b1b008000002"}, pseudo: 'John' });
Mongoose tries to cast it to ObjectId and fails. That's apart from the fact that pseudo field isn't in the group schema.
Try this instead:
Db.Members.push({User: mongoose.Types.ObjectId("521014731e27b1b008000002"), updated_at: whatever});