MongoDb.js / Mongoose find() translate a String in ObjectId - node.js

I have two schemas utilizing Mongoose
Schema 1
var schema = mongoose.Schema({
name: {
type: String,
required: true
}
});
return mongoose.model('User', schema);
Schema 2
var schema = mongoose.Schema({
name: {
type: String,
required: true
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
}
});
return mongoose.model('Page', schema);
My Data in Page Collection
_id
551b0cdf63dc96e9c39de0f8
551b0d1563dc96e9c39de0f9
551b0d2d63dc96e9c39de0fa
551b0d4363dc96e9c39de0fb
551daae0f4cb312c62dcbc1e
name
Cazaquistao
Russia
China
Australia
El Salvador
user
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7aaaf6d59fea26d7185
5515c7c9af6d59fea26d7186
when i search in schema 2 by user, I dont find any results.
The mongoose translate the mongoose converts the query erroneously.
Query
var test = Page.find().select("_id").where({"user" : "5515c7aaaf6d59fea26d7185"}).exec()
.then(function (t) {
console.log("hi", t);
});
Query Translated erroneously
db.pages.find({ user: ObjectId("5515c7aaaf6d59fea26d7185") })
no results
Query as it should be
db.pages.find({ user: "5515c7aaaf6d59fea26d7185" })=
4 results
Any suggestions of what to do to work around this?

If user is a string in your page docs, then your schema needs to reflect that or Mongoose will try and cast it to the type in your schema (ObjectId in this case).
So make user a string in the schema:
var schema = mongoose.Schema({
name: {
type: String,
required: true
},
user: {
type: String,
ref: 'User',
required: true
}
});

I solved passing a objectId rather than a String

Related

How to access and populate a referenced object schema in a larger document (MERN)

Making an app with a variety of schemas, many having other objects (Schema.Types.ObjectIds) as their properties.
When doing this, I can access the sub-object's property, as long as that sub-object's property is a string. But I'm having issues with it if that sub-object's property is yet another object (and then I need to query properties from that, string or not). For example, the first works fine:
user schema-> friends property of user (which is a list of user objects) -> username property of friend (which is a string)
But this I'm having issues with, I'm getting a string id and not the actual object**:
user schema-> profilePosts property of user (which is a list of profilePost objects) -> author property of profilePost (which is a user object)** -> author username property of profilePost (which is a string)
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {type: String, required: true},
password: {type: String, required: true},
friends: [{type: Schema.Types.ObjectId, ref: "User"}],
profilePosts: [{type: Schema.Types.ObjectId, ref: "ProfilePost"}],
friendRequests: [{type: Schema.Types.ObjectId, ref: "User"}],
})
module.exports = mongoose.model('User', UserSchema);
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ProfilePostSchema = new Schema({
date: {type: Date, required: true},
author: {type: Schema.Types.ObjectId, ref: "User"},
content: {type: String, required: true},
comments: [{type: Schema.Types.ObjectId, ref: "ProfilePostComment"}],
likes: [{type: Schema.Types.ObjectId, ref: "User"}],
hostProfile: {type: Schema.Types.ObjectId, required: true,ref: "User"},
})
module.exports = mongoose.model('ProfilePost', ProfilePostSchema);
exports.user_friends_render = async (req,res) => {
try {
const ViewedProfile = await User.find({}, 'username friends profilePosts friendRequests').populate('friends').populate('profilePosts').populate('friendRequests');
res.status(200).json(ViewedProfile);
} catch(error) {
res.status(200).json({message: error.message});
}
}
objects are string ids instead of objects
Mongoonse populate root object but not implicit deep populate
You can replace string by object as argument at populate method,
for provide full path to populate
const ViewedProfile = await User
.find({}, 'username friends profilePosts friendRequests')
.populate('friends')
.populate({
path: "profilePosts",
populate: [
{
path: "author",
// model: UserModel
},
{
path: "comments",
// model: ProfilePostCommentModel
},
{
path: "likes",
// model: UserModel
},
{
path: "hostProfile",
// model: UserModel
}
]
})
.populate('friendRequests');
You can see fully post at this problem.

How to set "capped" after collection is created?

I am attempting to set a capped parameter to my collection within my mongoose.Schema that did not include capped at first.
Any help welcome.
My Schema:
const mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: { type: String, required: true },
email: { type: String },
password: { type: String },
isAdmin: {type: Boolean, default: false},
avatar: { type: String },
joinDate: { type: Date, default: Date.now() },
},{ autoCreate: true, capped : 1024})
userSchema.set('timestamps', true);
const Users = mongoose.model('Users', userSchema)
module.exports = Users;
I get following error:
Error: A non-capped collection exists with the name: users
To use this collection as a capped collection, please first convert it.
Seems like you have already created a users collection in your database. So to convert it into a capped run below command either in mongoshell or robomongo
db.runCommand( { convertToCapped: 'users', size: 1024 } )

How to dynamically populate array of objects in mongoose?

I am trying to dynamically populate array of objects in mongoose. On my user model I want an array that contains all posts that user made. The problem is that I have multiple types of posts.
Different post models:
const ImagePost = mongoose.model('ImagePost', new Schema({ url: String }))
const TextPost = mongoose.model('TextPost', new Schema({ text: String }))
My user model looks like this:
const userSchema = new Schema({
userName: {
type: String,
required: true
},
posts: [{
postId: {
type: Schema.Types.ObjectId,
required: true,
refPath: "postModel"
},
postModel: {
type: String,
required: true,
enum: ['ImagePost', 'TextPost']
}
}]
})
const User = mongoose.model('User', userSchema)
How can I get the user from my database and automatically populate the posts the user made?
The whey I think it should work is this but for some reason it doesn't do anything:
User.findById('5d302c7caf1b8906ccb611b6').populate('posts.postId')
Changing your refPath from postModel to posts.postModel may solve your problem.

Match specific value in mongoose populate

Following is the schema of a user collection:
const Mongoose = require('mongoose')
const Schema = Mongoose.Schema
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String
},
supporterOf: [{
type: Schema.Types.ObjectId,
ref: 'individual',
required: false
}],
})
module.exports = Mongoose.model('user', userSchema);
I want to populate 'supporterOf' which is a collection of individual (ref: individual).
The 'supporterOf' contains an array of ObjectId.
I am having the problem of matching the specific objectId with that ObjectId array.
Can anyone suggest me how I can match specific ObjectId with an array of ObjectIds in populate function?
You have a reference of 'individual' in supporterOf and you want to populate only relevant object from the array of individuals?
If this is right case then do the following:
YourUserModel.findById(userId, function (err, user) {
console.log(user)
}).populate({
path: 'supporterOf',
match: {
yourObjectOfIndividualDocument: yourMatchingIdOfIndividual
}
})
.exec()
Replace yourObjectOfIndividualDocument: yourMatchingIdOfIndividual by name: 'abcd'.
Here name is the field of Individual document not of User document.
You add condition in populate
if you wanted to populate fans array based on their age, and return, at most, any 5 of them
.populate('fans', null, { age: { $gte: 21 }}, { limit: 5 })

Mongoose- How to reference embed document element?

I have users.js schema with a embeded document array pets. For each user, a user can have multiple pets(usually no more than 3 I would think).
For each pet, there would be a daily chart. So it would be many daily charts for a pet. I have read with embedded documents that each array element is indexed. In daily.js, how can I reference the pet it would belong to for the populate() function?
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
username: { type: String, required: true, unique: true },
location: String,
pets: [{ name: 'string', animalType: 'string'}], //could have more than one pet
created_at: Date,
updated_at: Date
});
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dailySchema = new Schema({
tite: String,
_pet: { type: Number, ref: 'User.pet' }, // not sure how to reference name in user.pets[#] array
created_at: Date,
updated_at: Date
});
Quoting
Sorry to disappoint but that is an anti-pattern. Populate can't populate from another collection's subdocs - the reason why you're getting that error is that there's no model for boards.
So it may be not good patten to reference to embedded document. It could be better to separate pet from User as one schema
var PetSchema = new Schema ({
name: 'string',
animalType: 'string'
});
And the UserSchema and DailySchema will be
var userSchema = new Schema({
...
pets: [{ type: Schema.Types.ObjectId, ref: 'Pet' }], //could have more than one pet
});
var dailySchema = new Schema({
_pet: { type: Number, ref: 'Pet' }, // not sure how to reference name in user.pets[#] array
});

Resources