So i'm trying to get profile data using API in Node.js but seems never get complete objects (for example avatar is missing from response)
i tried to console.log the object it went perfectly fine
Here is the server code:
router.get('/users/me', auth, async (req, res) => {
try {
const me = await User.findById(req.user._id)
console.log(me)
res.send(me)
} catch (e) {
res.status(500).send(e)
}
})
Here is response on console:
{ avatar:
'https://wisapedia-uploads.s3.amazonaws.com/default_ava.png',
bookmarks: [],
trips: [],
verified: false,
_id: 5d67b4155a032f3450c8ca03,
name: 'Syauqi',
password:
'$2a$08$LwLJPrp6MPdffkpJ1T2iN.QFbMDU5gAsSceNZVzU8tfDe5aUjGfFO',
email: 'ahmadthariq#gmail.com',
number: 85786135661,
birthday: 1997-04-01T16:00:00.000Z,
tokens:
[ { _id: 5d67b4155a032f3450c8ca04,
token:
'eyJhbGciOiJIUzI1NiIsI4gdCI6IkpXVCJ9.eyJfaWQiOiI1ZDY3YjQxNTVhMDMyZjM0NTBjOGNhMDMiLCJpYXQiOjE1NjcwNzczOTd9.i-r2wB6BoqK7cSoIxBiWB6SSESoCk3S5G_sW5PMz09s' } ],
createdAt: 2019-08-29T11:16:37.516Z,
updatedAt: 2019-08-29T11:16:37.572Z,
__v: 1 }
Here is what i got on postman:
{
"bookmarks": [],
"trips": [],
"verified": false,
"_id": "5d67b4155a032f3450c8ca03",
"name": "Syauqi",
"email": "ahmadthariq#gmail.com",
"number": 85786135661,
"birthday": "1997-04-01T16:00:00.000Z",
"createdAt": "2019-08-29T11:16:37.516Z",
"updatedAt": "2019-08-29T11:16:37.572Z",
"__v": 1
}
Thank you
Related
My question is:
How can I query in the nested arrays?
I want to change value in key "likeUp" which is nested inside object in array "usersWhoLiked". Where "usersWhoLiked" is nested in array "comments"
How Can I do that with mongoose ?
Request that I wrote beneath... do not work, but is very similar to answer given in StackOverflow post: Mongoose update update nested object inside an array
This is my request to db with updateOne:
try {
const response = await Comments.updateOne(
{
productId,
comments: { $elemMatch: { usersWhoLiked: { $elemMatch: { userId } } } },
},
{
$set: { 'comments.$[outer].usersWhoLiked.$[inner].likeUp': likes.up },
},
{
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
}
).exec();
return res.status(201).json({ response });
} catch (err) {
console.log(err);
return res.send(err);
}
This is the collection, that I am trying to update:
{
"_id": {
"$oid": "6307569d2308b78b378cc802"
},
"productId": "629da4b6634d5d11a859d729",
"comments": [
{
"userId": "62f29c2c324f4778dff443f6",
"userName": "User",
"date": "2022.08.25",
"confirmed": true,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 5,
"description": "Nowy komentarz"
},
"_id": {
"$oid": "630756b22308b78b378cc809"
},
"usersWhoLiked": [
{
"userId": "62f29c2c324f4778dff443f1",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80e"
}
},
{
"userId": "62f29c2c324f4778dff443f2",
"likeUp": true,
"_id": {
"$oid": "6307572d2308b78b378cc80c"
}
}
]
}
],
"__v": 0
}
Mongooes schema for comment collection:
const commentSchema = new Schema({
productId: String,
comments: [
{
userId: String,
userName: String,
date: String,
confirmed: Boolean,
likes: {
up: {
type: Number,
default: 0,
},
down: {
type: Number,
default: 0,
},
},
content: {
rating: Number,
description: String,
},
usersWhoLiked: [{ userId: String, likeUp: Boolean }],
},
],
});
I guess the problem is with your arrayFilters operator, because you are trying to filter by field _userId which does not exist:
arrayFilters: [{ 'outer._id': commentId }, { 'inner._userId': userId }],
I managed to update the likeUp value using the following query:
db.collection.update({
_id: ObjectId("6307569d2308b78b378cc802")
},
{
$set: {
"comments.$[user].usersWhoLiked.$[like].likeUp": false
}
},
{
arrayFilters: [
{
"user._id": ObjectId("630756b22308b78b378cc809")
},
{
"like.userId": "62f29c2c324f4778dff443f1"
}
]
})
Try it on MongoDB playground: https://mongoplayground.net/p/XhQMNBgEdhp
In ImageSchema, I have some fields - title, imageURL. When I retrieving single image data, I want to add http://localhost:4000/ to imageURL.
"imageURL": "http://localhost:4000/uploads/photo-1508919801845.jpeg",
Example data:
{
"_id": "612e0328c1c6dd25c6f14fd4",
"title": "photo-1508919801845",
"imageURL": "/uploads/photo-1508919801845.jpeg",
"createdAt": "2021-08-31T10:23:36.419Z",
"updatedAt": "2021-08-31T10:23:36.419Z",
"__v": 0
}
Controller.ts
const imageId = req.params.id
const findImage = await Image.findOne({ _id: imageId})
if (!findImage) {
return res.status(404).json({error: true, msg: "Image not found"})
}
const image = await Image.findById({_id: imageId}).select({ _id: 0, __v: 0})
return res.status(200).json({ error: false, data: image })
How can I do that?
You can use Aggregation pipeline with $concat operator:
Image.aggregate([
{
"$match": {
"_id": "612e0328c1c6dd25c6f14fd4"
}
},
{
"$set": {
"imageURL": {
"$concat": [
"http://localhost:4000",
"$imageURL"
]
}
}
}
])
Working example
I'm trying to reduce my API data size to remove unwanted data. I have schema like this
const course = mongoose.Schema(
{
course_name: { type: String, require: true },
disabled: { type: String, required: true, default: false },
subject_ids: [
{
type: mongoose.Schema.ObjectId,
ref: 'subject',
require: true,
},
],
},
{ timestamps: true }
);
after applying the find query i have data like this
{
"disabled": "false",
"subject_ids": [
{
"disabled": "false",
"_id": "60b0bdd5cd7bd635ecf07cd5",
"subject_name": "CSS",
"createdAt": "2021-05-28T09:54:29.147Z",
"updatedAt": "2021-05-28T09:54:29.147Z",
"__v": 0
},
{
"disabled": "false",
"_id": "60b0bdd5cd7bd635ecf07cd7",
"subject_name": "Jquery",
"createdAt": "2021-05-28T09:54:29.147Z",
"updatedAt": "2021-05-28T09:54:29.147Z",
"__v": 0
}
],
"_id": "60b0e3f3012b2b272432e9f9",
"course_name": "Data Science",
"createdAt": "2021-05-28T12:37:07.103Z"
}
API
I have tried something like this. I already remove data from the outside array, but I don't know how I can remove it from the inside. I do lots of google search but I didn't get
router.get('/get-course/:status', async (req, res) => {
try {
const data = await COURSE.find({})
.populate('subject_ids')
.select({ updatedAt: 0, __v: 0 })
.exec();
res.json(data);
} catch (error) {
res.status(404).json({ err: 1, message: error.message, error });
}
});
I want data should be like this
{
"disabled": "false",
"subject_ids": [
{
"_id": "60b0bdd5cd7bd635ecf07cd5",
"subject_name": "CSS",
},
{
"_id": "60b0bdd5cd7bd635ecf07cd7",
"subject_name": "Jquery",
}
],
"_id": "60b0e3f3012b2b272432e9f9",
"course_name": "Data Science",
"createdAt": "2021-05-28T12:37:07.103Z"
}
How to get specific data from array
Try this
router.get('/get-course/:status', async (req, res) => {
try {
const data = await COURSE.find({})
.populate('subject_ids')
.select({
updatedAt: 0,
__v: 0,
subject_ids.disabled: 0,
subject_ids.createdAt: 0
subject_ids.updatedAt: 0
subject_ids.__v: 0
})
.exec();
res.json(data);
} catch (error) {
res.status(404).json({ err: 1, message: error.message, error });
}
});
Try this:
populate('subject_ids','subject_name').exec()
U can use
router.get('/get-course/:status', async (req, res) => {
try {
const data = await COURSE.find({})
.select("-subject_ids.disabled -subject_ids.createdAt -subject_ids.updatedAt -subject_ids.__v")
.exec()
res.json(data);
} catch (error) {
res.status(404).json({ err: 1, message: error.message, error });
}
});
The
.select("-parentArray.child")
excludes the child property of all elements in the Array.
I'm having hard time on thinking how will I populate hooks with API response(json)
see below codes
cosnt [loginResponse, setloginResponse] = useState({
Token: '',
UserID: '', //from user-id
UserName: '', //from user-userName
firstName: '', //from user-firstName
rcCode: '' //from attributes-rcCode
})
const login = async () => {
await axios.get('/API')
.then(response => {
console.log('response.data', response.data.resp)
});
}
here's the result of console.log(response.data.resp)
{
"data": {
"token": "abcd",
"user": {
"id": "123456",
"userName": "uname",
"firstName": "FNAME",
"lastName": "MNAME",
"email": "email#email.com",
"attributes": {
"favorites": ["FAV"],
"rcCode": ["123"]
},
"requiredActions": [],
"roles": ["ROLE"]
},
"modulePermissions": []
}
}
for console.log(response.data):
"resp": {
"data": {
"token": "abcd",
"user": {
"id": "123456",
"userName": "uname",
"firstName": "FNAME",
"lastName": "MNAME",
"email": "email#email.com",
"attributes": {
"favorites": ["FAV"],
"rcCode": ["123"]
},
"requiredActions": [],
"roles": ["ROLE"]
},
"modulePermissions": []
}
},
"success": true
I want to populate my hooks with those datas for me to utilize it on my page.
I got undefined if I tried to console.log(response.data.resp.data)
On console.log(response), I got:
Thank you.
Don't use async/await and .then() together. Use either of those.
const login = async () => {
const response = await axios.get('/API');
const parsedData = JSON.parse(response.data.resp);
const userData = parsedData.data;
setLoginResponse({
Token: userData.token,
UserID: userData.user.id,
UserName: userData.user.userName,
firstName: userData.user.firstName,
rcCode: userData.user.attributes.rcCode
});
}
In the .then
setLoginResponse({...loginResponse, Token: response.data.resp.data.token, UserId: response.data.resp.data.user.id, ...}
You can destructure your response object first and store values in variables to make the setLoginResponse more easy to read.
https://reactjs.org/docs/hooks-state.html
I've been building a mongoose schema for texts that will be displayed across different pages, and it has end point to POST data for updating the texts.
For example, I would like to store text messages that will be displayed/updated in About Page and Contact Page
What would be the preferred way of designing the text model?
1) Model that has all messages stored in one data object
In front-end, the parent component fetches all text messages with Texts.findOne() and trickles down to pages that need it
const textsSchema = new Schema(
{
aboutMessage1: {
type: String,
required: true
},
aboutMessage2: {
type: String,
required: true
},
contactMessage1: {
type: String
},
contactMessage2: {
type: String
}
},
{ timestamps: true }
);
2) Model that contains each message--so it will have multiple objects
In fron-end, each page uses Text.findById(textId) to retrieve each message
const textSchema = new Schema(
{
// Example: name = contactMessage
name: {
type: String
},
message: {
type: String
}
},
{ timestamps: true }
);
3) Multiple models that contains texts for each page
Similar to 1) approach, texts get fetched with Texts.findOne(), but performed in each page
const aboutTextsSchema = new Schema(
{
message1: {
type: String,
required: true
},
message2: {
type: String,
required: true
},
},
{ timestamps: true }
);
const contactTextsSchema = new Schema(
{
message1: {
type: String,
},
message2: {
type: String,
},
},
{ timestamps: true }
);
The most promising option is the second one. Because first and third options are static, and if in the future, you need to add a new page or or a new message to an existing page, it will require changes in the mongoose model, and deployment for API.
But I think, instead of creating a text schema, it would better to create a page schema for your scenario.
Here I embed messages inside the page schema.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const pageSchema = new Schema(
{
page: {
type: String
},
messages: [
new Schema({
name: {
type: String
},
message: {
type: String
}
})
]
},
{ timestamps: true }
);
module.exports = mongoose.model("Page", pageSchema);
Now we can use this post route to create a page:
router.post("/pages", async (req, res) => {
const result = await Text.create(req.body);
res.send(result);
});
We can create a page and its messages using the previous post route.
Request Body:
{
"_id": "5e4937e9e2454a2c0c162890",
"page": "About",
"messages": [
{
"_id": "5e4937e9e2454a2c0c162892",
"name": "Abou1",
"message": "About1 message..."
},
{
"_id": "5e4937e9e2454a2c0c162891",
"name": "Abou2",
"message": "About2 message..."
}
],
"createdAt": "2020-02-16T12:39:05.154Z",
"updatedAt": "2020-02-16T12:39:05.154Z",
"__v": 0
}
Response:
{
"_id": "5e4937e9e2454a2c0c162890",
"page": "About",
"messages": [
{
"_id": "5e4937e9e2454a2c0c162892",
"name": "Abou1",
"message": "About1 message..."
},
{
"_id": "5e4937e9e2454a2c0c162891",
"name": "Abou2",
"message": "About2 message..."
}
],
"createdAt": "2020-02-16T12:39:05.154Z",
"updatedAt": "2020-02-16T12:39:05.154Z",
"__v": 0
}
If later we want to add a message to a page we can use the following put route.
router.put("/pages/:id", async (req, res) => {
const result = await Page.findByIdAndUpdate(
req.params.id,
{
$push: { messages: req.body }
},
{ new: true }
);
res.send(result);
});
Request Body:
{
"name": "Abou3",
"message": "About3 message..."
}
Response:
{
"_id": "5e4937e9e2454a2c0c162890",
"page": "About",
"messages": [
{
"_id": "5e4937e9e2454a2c0c162892",
"name": "Abou1",
"message": "About1 message..."
},
{
"_id": "5e4937e9e2454a2c0c162891",
"name": "Abou2",
"message": "About2 message..."
},
{
"_id": "5e493926f905ab3300106f94",
"name": "Abou3",
"message": "About3 message..."
}
],
"createdAt": "2020-02-16T12:39:05.154Z",
"updatedAt": "2020-02-16T12:44:22.763Z",
"__v": 0
}
When client needs a page's messages, all we need to do is retrieving the page by it's id or page name:
router.get("/pages/id/:id", async (req, res) => {
const result = await Page.findById(req.params.id);
res.send(result);
});
//or
router.get("/pages/name/:name", async (req, res) => {
const result = await Page.findOne({ page: req.params.name });
res.send(result);
});