I'm not sure how to explain the following, but I hope I can make myself understood. I am doing a moongose compatible query in NodeJS. That works fine, I do a search and some padding to get the expected result, but there is something I don't understand. I am doing this query through a regEx as I am searching by string parameter. When I do it this way I get something like this:
{
"affiliate": {
"0": {
...content
}
}
}
//The code of the before res using finde in affiliate
export const getAffiliateWithUserName = async (req: Request & any, res: Response, next: NextFunction) => {
try {
const userName: string = req.params.userName;
const affiliate = await Affiliate.find({ "userName": { $regex: userName, $options: "i" } }).populate({
path: "attentionSchedules",
select: "place floor room schedules -affiliate -_id",
populate: { path: "place", select: "name address loc" },
match: { enabled: true }
}).exec();
const affiliateId = affiliate.map(id=> id._id);
const idToString = affiliateId.toString();
const affiliateObjectId = Types.ObjectId(idToString);
const servicesByAff = await ServicesByAffiliate.find({
affiliate: affiliateObjectId,
enabled: true
}).populate("service").populate("category").populate("subCategory").populate("place").populate({
path: "appointmentRequiredService",
populate: { path: "category service" }
}).exec();
console.log(servicesByAff);
const groupedServices = servicesByAff.reduce((acc, serviceByAff) => {
if (serviceByAff.service.isVirtual) {
acc.virtual.push(serviceByAff);
} else if (serviceByAff.service.isDomicilio) {
acc.atHome.push(serviceByAff);
} else {
acc.clinic.push(serviceByAff);
}
return acc;
}, { virtual: [], atHome: [], clinic: [] });
const convertToObject = Object.assign({}, affiliate);
res.status(200).json({
affiliate: { ...convertToObject, groupedServices },
});
// res.json({ affiliate });
} catch (error) {
res.status(500).json({
error: true,
message: error.message,
});
}
};
It's like a nested object, but when I perform my query with findOne passing the schema id as a parameter, the result I get is:
{
"affiliate":{
...content
}
}
//The code use findOne in affiliate
export const groupedServices = async (req: Request & any, res: Response, next: NextFunction) => {
try {
const {affiliateId} = req.params;
const affiliateObjectId = Types.ObjectId(affiliateId);
const affiliate = await Affiliate.findOne(affiliateObjectId).populate({
path: "attentionSchedules",
select: "place floor room schedules -affiliate -_id",
populate: {path: "place", select: "name address loc"},
match: {enabled: true}
}).exec();
const servicesByAff = await ServicesByAffiliate.find({
affiliate: affiliateObjectId,
enabled: true
}).populate("service").populate("category").populate("subCategory").populate("place").populate({
path: "appointmentRequiredService",
populate: {path: "category service"}
}).exec();
console.log(servicesByAff);
const groupedServices = servicesByAff.reduce((acc, serviceByAff) => {
if (serviceByAff.service.isVirtual) {
acc.virtual.push(serviceByAff);
} else if (serviceByAff.service.isDomicilio) {
acc.atHome.push(serviceByAff);
} else {
acc.clinic.push(serviceByAff);
}
return acc;
}, {virtual: [], atHome: [], clinic: []});
res.status(200).json({
affiliate: {...affiliate.toObject(), groupedServices},
});
} catch (e) {
res.status(500).json({
error: true,
message: e.message,
});
}
};
And I need to display my result as the second example, what could it be? Does it have something to do with the way I display my result? Is it some moongose? Could someone give me some recommendation?
Related
I am currently designing a multi-users chat application in solid-js. When a user sends a message in the chat, the message is saved in the database but no message is shown to the participants. Here is the content of my index.jsx file:
import { fetchMessages } from "../../../../services/chat.service";
...
export default function ChatSpace() {
const params = useParams();
const [response, { refetch }] = createResource( () => params.chatId,fetchMessages);
return (
...
...
<Match when={response()?.data.data.messages.length !== 0}>
<For each={response()?.data.data.messages}>
{(message) => (<Message {...message} refetch={refetch}/>)}
</For>
</Match>
...
)
Here is the content of my fetchMessages.js file:
const { db } = require("../../utils/db");
const { includeChatMessage } = require("./_helper");
exports.fetchMessages = async (req, res, next) => {
try {
const chatId = req.params.chatId;
const chat = await db.chatMessage.findUnique({
where: { id: chatId },
select: {
members:{
id: true,
firstName: true,
lastName: true,
profileImage: true,
status: true,
lastSeen: true,
socketId: true,
},
},
});
const messages = await db.chatMessage.findMany({
where: {
chatId,
},
include: includeChatMessage,
});
return res.status(200).json({
type: "success",
message: "Fetch messages between users",
data: {
messages,
chat,
},
});
} catch (error) {
next(error);
}
};
my _helper.js file:
const { db } = require("../../utils/db");
exports.includeChatMessage = {
sender: {
select: {
id: true,
firstName: true,
lastName: true,
profileImage: true,
status: true,
},
},
chat: {
select: {
id: true,
},
},
};
I don't understand why, it doesn't show user messages yet no error not even warning is shown in browser or code editor console.
I have a route that is /mysafe/idofthemodel. When the idofthemodel isn't found it throws a cast error Cast to ObjectId failed for value "something" (type string) at path "_id" for model "modelname". Instead of the error I would like to have a 404 error.
Here is my route
app.get('/mysafe/:safeid',isLoggedIn,isAuthor, async(req,res)=> {
const { safeid } = req.params;
const safe=await Safe.findById(safeid).populate('author')
const password = await Password.find({safe:safeid}).populate('safe')
res.render('passwords/index', { password,safe })
})
Schemas:
const PasswordsSchema = new Schema({
title: String,
url: String,
password: String,
safe: {
type: Schema.Types.ObjectId,
ref: "Safe"
},
})
const SafeSchema = new Schema({
author: {
type: Schema.Types.ObjectId,
ref: "User"
},
})
Here I'm using EJS to render the 404 Error page,
and the page file is located in views/errors/404.ejs
const { safeid } = req.params;
try {
const safe = await Safe.findOne({ _id: mongoose.Types.ObjectId(safeid) }).populate('author')
if (!safe) {
return res.status(404).render('errors/404.ejs')
}
const password = await Password.findOne({ safe: mongoose.Types.ObjectId(safeid) }).populate('safe')
return res.render('passwords/index', { password, safe })
}
catch (error) {
return res.status(500).render('errors/500')
}
middleware.js
module.exports.isAuthor = (req, res, next) => {
const { safeid } = req.params
if (!mongoose.Types.ObjectId.isValid(safeid)) {
return res.status(404).render('errors/404.ejs')
}
Safe.findById(safeid).then(safe => {
if (!safe) {
return res.status(404).render('errors/404.ejs')
}
if (!safe.author._id.equals(req.user._id)) {
req.flash('error', 'Notfound');
return res.redirect('/');
}
next();
});
}
I came to a problem, where I can create conversations with multiple people 2 and so on. However, I can't understand why it doesn't store data to seperate User models.
Here is a code that you only need to know:
router.post(
"/",
auth,
[
check("conversators", "There should be at least two conversators").isLength(
{ min: 2 }
),
],
async (req, res) => {
const { conversators } = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
let conversation = new Conversation({
user: req.user.id,
conversators: conversators,
});
await conversators.map(async (conversator) => {
let user = await User.findById(conversator);
let newData = user;
newData.conversations.push(conversation.id);
console.log('Created data', newData);
let newUser = await User.findOneAndUpdate(
{ user: conversator },
{
$set: {
newData,
},
},
{ new: true }
);
await newUser.save();
console.log(newUser);
});
await conversation.save();
res.status(200).json(conversation);
} catch (error) {
console.error(error.message);
res.status(500).send("Server error.");
}
}
);
module.exports = router;
What I can assure is that this line: console.log('Created data', newData); prints the desired data. However, the next console: console.log(newUser); prints the same User model as the previous one.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
surname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
conversations: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "conversation",
},
],
date: {
type: Date,
default: Date.now,
},
});
module.exports = User = mongoose.model("user", UserSchema);
The reason might be the difference in search methods used to get a record for newData and newUser. You have used User.findById for newData, which will obviously return different objects for different ids. But User.findOneAndUpdate uses filter criteria that may satisfy several results, but only first will be returned. So it boldly depends on what that user field is.
Here is the part that I changed and started to see the data on MongoDB:
await conversators.map(async (conversator) => {
let user = await User.findById(conversator);
let newData = user;
newData.conversations.push(conversation.id);
new Promise(async (resolve, reject) => {
user = await User.findOneAndUpdate(
{ id: conversator },
{
$set: {
newData,
},
},
{ new: true }
);
return resolve;
})
return await user.save();
});
Posted on behalf of the question asker
want to fetch all users but just return list of _ids , checked the saved data in db everything seems good.
this is the user model
let UserSchema = new mongoose.Schema({
firstName: {
type: String,
minlength: 3,
trim: true,
},
lastName: {
type: String,
minlength: 3,
trim: true,
},
biography: {
type: String,
minlength: 5,
trim: true,
},
});
UserSchema.methods.toJSON = function () {
let user = this;
let userObject = user.toObject();
return _.pick(userObject, ["_id", "firstName", "email"]);
};
and this is my controller function
const controller = {
fetchUsers :async (_req, res) => {
try {
await User.find({})
.then((users) => {
res.status(200).send(users);
})
.catch((err) => {
res.status(400).send(err);
});
} catch (error) {
res.status(400).json({
Error: `something is wrong. ${error}`,
});
}
}
}
the result is that i tested in postman is :
[
{
"_id": "5fe26ba0d290a216c0fe6d5d"
},
{
"_id": "5fe26c8e40ca9a06b8c96259"
},
]
Don't use .then & await both . Try this once. Assuming model is correct.
const controller = {
fetchUsers :async (_req, res) => {
try {
const users=await User.find({}).exec()
if(users){
res.status(200).send(users);
}
else{
res.status(404).send("no user found");
};
} catch (error) {
res.status(500).json({
Error: `something is wrong. ${error}`,
});
}
}
}
problem is UserSchema.methods.toJSON method there isn't any email field, if we want to filter our output data it's better to filter it by mongoose.find({"condition"},{"fields"})
I trying to implement a favorite toggle where it saves the favorites in an array, I create a Schema and a router, the code you can see below the problem is when I try to test it on insomnia I'm getting undefined on my console.log(isFavorite). I don't know what could be wrong.
const userSchema = new Schema({
username: String,
email: String,
password: String,
favorites: [{ type: Schema.Types.ObjectId, ref: "Places" }],
},
{
timestamps: true,
});
// route
router.put("/favorites/:placeId", (req, res) => {
const userId = "5ebd13df31430045957db8c3";
User.findById(userId).then( (user) => {
const isFavorite = user.favorites.find( (favorite) => {
return favorite === req.params.placeId;
});
console.log(isFavorite);
console.log(req.params.placeId);
if (isFavorite) {
User.findOneAndUpdate(
{ _id: userId },
{
$pull: { favorites: req.params.placeId },
},
{
new: true,
})
.then((user) => res.json(user))
.catch((err) => res.status(400).json(err));
} else {
User.findOneAndUpdate(
{ _id: userId },
{
$push: { favorites: req.params.placeId },
},
{
new: true,
})
.then((user) => res.json(user))
.catch((err) => res.status(400).json(err));
}
});
});
this chunk is bad:
User.findById(userId).then((user) => {
const isFavorite = user.favorites.find((favorite) => {
return favorite === req.params.placeId;
});
instead must use populate():
let favorites = await User.findById(userId).populate('favorites');
and then filter favorites by placeId