MongoDB Get Field to Update a Value from Request Query - javascript

I have user object structured like this:
{
"id": "",
"username": "",
"name": "",
"bio": "",
"email": "",
"profileImg": "",
"phoneNumber": 0,
"messagingPoints": 0,
"funds": 0,
"inventoryId": "",
"lastLogin": "2022-02-23T03:27:13.535Z",
"isPrivate": false,
"messagesReceived": []
}
I want to be able to reach a patch endpoint to update any of these fields. For example, /api/user?id=userId&name=John, should be able to grab the field "name" and set it to John. /api/user/id=?id=userId&email=abc#gmail.com should grab the email field and set it to abc#gmail.com
I am struggling to find docs for MongoDB to accomplish this, so I'm wondering if it is not possible? Do I need a specific endpoint for each of these update operations (ex: /api/user/name?id=userId&value=John instead of /api/user?id=userId&name=John)?
If it is possible, how could I accomplish this? Thanks!

You can pass user ID in update filter. Also you can pass data in request body of the PUT request instead of query parameters.
app.put('/api/user', async (req, res) => {
const { id, ...data } = req.body;
// Filter out any invalid fields
// Update documents where id field is equal to value of id in request body
await collection.updateOne(
{ id },
{ $set: data }
);
return res.json({ data: "User updated" })
})

Related

Remove element from Multiple MongoDB Array simultaneously

I am creating MERN Classroom where users can Create/Join classes using the class's unique Code. Whenever a user joins the classroom, class id gets pushed into the User's MongoDB document array (classesJoined) and the user id gets pushed into Classroom's MongoDB document array (classroomMembers)
Updated User's Document:
{
"_id": "62e7ef5f636d28247a21b1e7",
"name": "User One",
"email": "userone#mydomain.com",
"password": "encryptedPassword",
"classesJoined": [
"62e7f00e636d28247a21b20d",
"62e7f0a0636d28247a21b247"
]
}
Updated Classroom's Document:
{
"_id": "62e7f00e636d28247a21b20d",
"classroomName": "Class by User One",
"classroomCode": "9ljsgNqx",
"classroomMembers": [
"62e7ef5f636d28247a21b1e7"
]
}
When a user wants to leave the classroom, the classroom's ID should be removed from the User document as well as the User ID should also be removed from the Classroom Document.
To achieve this, I have tried this logic in my Express Server route:
try{
await Users.findByIdAndUpdate({_id: req.body.userID}, { $pull: { classesJoined: req.body.classID } })
await Classroom.findByIdAndUpdate({_id: req.body.classID}, { $pull: { classroomMembers: req.body.userID }
res.send("Class Removed")
})
} catch (error){
res.send("Error Occured")
}
POST Request Body Contains:
{
"userID": "62e7ef5f636d28247a21b1e7",
"classID": "62e7f00e636d28247a21b20d",
}
But the problem I am facing is that the User ID from Classroom.classroomMembers gets removed but in User Document, nothing is changing or showing an error. The classesJoined array keeps the same element.

Can't query by ID as second parameter with AWS DataStore

I am total noob to AWS, DataStore, and DynamoDB. I can't figure out why this isn't working.
If I attempt query an object related to my users ID from Cognito this seems to work. If I console log I get an array with one User.
let profile = await DataStore.query(User, (u) =>
u.id('eq', user.attributes.sub)
);
// Returns [Model]
console.log('[LOADING USER DATA]', profile);
If I attempt query an object related to my users ID like this. (as recommended by the docs). I get undefined.
let profile = await DataStore.query(User, user.attributes.sub);
// Returns undefined
console.log('[LOADING USER DATA]', profile);
Dynamo Data looks fine to me but am I using the wrong primary key ID field or something?
{
"id": "929e6e62-e3a0-4b84-b050-72c53eebda93",
"_lastChangedAt": 1644433699,
"status": "Active",
"createdAt": "2022-02-09T19:08:18.548Z",
"name": "Test",
"orgs": [
"b6508155-f5cf-49b7-88d6-0e605677c4e4"
],
"_version": 1,
"role": "User",
"updatedAt": "2022-02-09T19:08:18.548Z",
"orgID": "b6508155-f5cf-49b7-88d6-0e605677c4e4",
"title": ""
}
What am I doing wrong?

Optimalization of firebase query. Getting data by ids

I'm new in Firebase. I would like to create an app (using Angular and AngularFire library), which shows current price of some wares. I have list all available wares in Firebase Realtime Database in the following format:
"warehouse": {
"wares": {
"id1": {
"id": "id1",
"name": "name1",
"price": "0.99"
},
"id2": {
"id": "id2",
"name": "name2",
"price": "15.00"
},
... //much more stuff
}
}
I'm using ngrx with my app, so I think that I can load all wares to store as an object not list because normalizing state tree. I wanted load wares to store in this way:
this.db.object('warehouse/wares').valueChanges();
The problem is wares' price will be refresh every 5 minutes. The number og wares is huge (about 3000 items) so one response will be weight about 700kB. I know that I will exceed limit downloaded data in a short time, in this way.
I want limit the loading data to interesing for user, so every user will can choose wares. I will store this choices in following way:
"users": {
"user1": {
"id": "user1",
"wares": {
"id1": {
"order": 1
},
"id27": {
"order": 2
},
"id533": {
"order": 3
}
},
"waresIds": ["id1", "id27", "id533"]
}
}
And my question is:
Is there a way to getting wares based on waresIds' current user? I mean, does it exist way to get only wares, whose ids are in argument array? F.e.
"wares": {
"id1": {
"id": "id1",
"name": "name1",
"price": "0.99"
},
"id27": {
"id": "id27",
"name": "name27",
"price": "0.19"
},
"id533": {
"id": "id533",
"name": "name533",
"price": "1.19"
}
}
for query like:
this.db.object('warehouse/wares').contains(["id1", "id27", "id533"]).valueChanges();
I saw query limits in Angular Fire like equalTo and etc. but every is for list. I'm totally confused. Is there anyone who can help me? Maybe I'm making mistakes in the design of the app structure. If so, I am asking for clarification.
Because you are saving the ids inside user try this way.
wares: Observable<any[]>;
//inside ngOnInit or function
this.wares = this.db.list('users/currentUserId/wares').snapshotChanges().map(changes => {
return changes.map(c => {
const id = c.payload.key; //gets ids under users/wares/ids..
let wares=[];
//now get the wares
this.db.list('warehouse/wares', ref => ref.orderByChild('id').equalTo(id)).valueChanges().subscribe(res=>{
res.forEach(data=>{
wares.push(data);
})
});
return wares;
});
});
There are two things you can do. I don't believe Firebase allows you to query for multiple equals values at once. You can however loop over the array of "ids" and query for each one directly.
I am assuming you already queried for "waresIds" and you've stored those ID's in an array named idArray:
for id in idArray {
database.ref('warehouse/wares').orderByChild('id').equalTo(id).once('value').then((snapshot) => {
console.log(snapshot.val());
})
}
In order to use the above query efficiently you'll have to index your data on id.
Your second option would be to use .childChanged to get only the updated data after your initial fetch. This should cut down drastically on the amount of data you need to download.
Yes , you can get exactly data that you want in firebase,
See official Firebase documents about filtering
You need to get each waresID
var waresID = // logic to get waresID
var userId = // logic to get userId
var ref = firebase.database().ref("wares/" + userId).child(waresID);
ref.once("value")
.then(function(snapshot) {
console.log(snapshot.val());
});
this will return only data related to that waresID or userId
Note: this is javascript code, i hope this will work for you.

Filter out unwanted data from Response

I am working on a service which uses restify and mongoose as odm.
Below is the service response which I get after DB call.
[
{
"_id": "5a548b7c025cfcffdd286e0f",
"createdAt": "2018-01-09T09:29:32.515Z",
"updatedAt": "2018-01-09T10:59:49.159Z",
"subject": "Hello buddy.",
"body": "i am good and fine.",
"category": "email service",
"category_id": "232",
"author": "5a5485834c2274ce5d5e54f8",
"__v": 0,
"images": [
"https://google.com"
],
"email content": [
{
"_id": "5a549dcb80a16b2e822357ae",
"createdAt": "2018-01-09T10:47:39.883Z",
"updatedAt": "2018-01-09T10:47:39.883Z",
"body": "my first comment",
"name": "asdf"
"password":"312312"
"__v": 0,
"photos": []
}
]
}]
Emails.find({_id: emaiId, author_id: author_id}).
populate('emailcontent').exec(function(err, listOfEmails) {
if (err) {
console.error(err);
return next(
new errors.InvalidContentError(err.errors.name.message),
);
}
res.send(listOfEmails);
next();
This is a small part of my response. Now, I do not want to send all the response back to the client. For example, username, password, phone no etc. So I have a lot of data which I do not want to send back. How do I do this in over here?
Delete these fields manually before sending data back:
listOfEmails.forEach(email => {
// for array properties
email['email content'].forEach(content => {
delete content.name;
delete content.password;
// ... and so on
});
// for usual properties
delete email._id;
});
res.send(listOfEmails);
Answers above are about black listing fields, but you can also try whitelisting, e.g.
const croppedEmails = emails.map( (email) => {
body: email.body,
...(rest of needed fields)
});
With this approach when you will add new field which is confidential you will not have to add new delete, on the other hand when adding new public field you will also need to add it to above function.
Oh, and there is also projection Mongoose, find, return specific properties
You can use map() to create a new array that you send as response. Use delete to delete fields.
const newListOfEmails = listOfEmails.map((email) => {
delete email._id;
delete email.createdAt;
delete email.updatedAt;
for (let eIdx = 0; eIdx < email["email content"].length; eIdx += 1) {
delete email["email content"][eIdx].password;
}
return email;
});
res.send(newListOfEmails);

#Sequelize while adding retrieve all attributes

I would like to find a way to retrieve all my attributes while inserting in my Database.
models.association.build(associationParams)
.save()
.then(function(assoAdded){
return next(assoAdded);
}).catch(function(err){
// # TODO : implement error Handler
return next(err);
});
I got this :
{
"idAssoParente": null,
"id": 420,
"name": "a",
"email": "aa#aa.aa",
"updated_at": "2015-07-29T17:12:47.000Z",
"created_at": "2015-07-29T17:12:47.000Z"
}
But I want to return all my fields like description , phone , city from my database even if they are empty. Should I necessarily do a find after adding to get all my fields or does it exist a way to retrieve my fields without doing an other request ?
Thanks
In short, yes you would need to query your db to return the info. I just started using Sequelize but I found the following worked for me.
// if all the info you need is in your user
Users.build({req.body})
.save()
.then(function(newUser){
Users.find({where: {UserID: newUser.UserID}}).then(function(user){
//resolve your promise as you please.
});
// or if address info is in another model you can use eager loading.
Users.build({req.body})
.save()
.then(function(newUser){
Users.find({where: {UserID: newUser.UserID},
include: [{
model: address
}]
}).then(function(user){
//resolve your promise as you please.
});

Categories

Resources