Add a new field for already existing resource using PUT - mongodb

I implemented google auth in my NextJS app. The idea is: user makes some progress working with my web app, I store this progress in local storage as an array. If he decides to register I receive the session back, then I send PUT request to db to update the document by inserting a new field (array) from local storage.
I implemented GET request that returns registered user data by email and it works. The question is, how to insert a new field using PUT method? In my case this field is array and calls progress. I'm not sure if I should use update.
This is the record from my mongodb:
_id: 63cc85641624a77f17ca5f29
name: "John P"
email: "john.p#gmail.com"
image: "https://lh3.googleusercontent.com/a/AEdFTp7xzF4eYtyhTgRxmgP4vYdCqDa6zW…"
emailVerified: null
I want to add a new field: progress: ['some data']
This is my PUT request:
case 'PUT':
const updateData = await fetch(`${baseUrl}/updateOne`, {
...fetchOptions,
body: JSON.stringify({
...fetchBody,
filter: { email: email },
update: {} <---------------!!!!!
}),
})
const updateDataJson = await updateData.json()
res.status(200).json(updateDataJson.documents)
break

If you want to update your document using updateOne, and add a progress key, you can use:
filter: { email: email },
update: {$set: {progress: arr}}

Related

Query db without certain elements inside an array

I set up a small database using a model and 2 schemas.
The model goes as follows:
const userSchema = new mongoose.Schema({
friendsRequests: [friendRequestSchema],
//other credentials that are not important//
});
And the friendRequestSchema:
const friendRequestSchema = new mongoose.Schema({
from: { type: Schema.Types.ObjectId, ref: "User" },
to: { type: Schema.Types.ObjectId, ref: "User" },
});
Basically friendsRequests is an array consisting of who requested to add the user to the friends list (which is the from property) and whom the user wants to add to their friends list (which is the to property).
For the query, I am trying to sort out how to send a response without containing the users that are inside the user's friendsRequests array.
If i do this :
const recFriends = await User.findOne({ _id: req.user }).select(
"friendsRequests"
);
i will get back the array with objects containing either sent or received requests. Now i want to query again the User model and have it not return elements from this array. How would i go about doing that?

How should I store multiple nested arrays, populated using Mongoose populate(), in the cache using React Query?

Apologies if this is basic but I'm struggling to get my head around how to set this up.
I'm using MongoDB/Mongoose for my backend which returns a user object with nested arrays:
{
username: {
type: String,
unique: true
},
name: String,
avatar: String,
recommendations: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Media' }],
watchlist: [{
media: { type: mongoose.Schema.Types.ObjectId, ref: 'Media' },
date_added: Date,
}],
}
If a user visits their watchlist or recommendations page, the nested array gets populated, using mongoose populate(), with the referenced recommendations/watchlist items that they've added.
On the frontend I'm using React Query to handle the data returned from the server. Currently visiting either of the pages returns the whole user object, if I were to cache the entire object using the query key ['user'] the nested array not being populated will be stored as an array of reference id's. Instead I was thinking of maybe trying to update the nested arrays using setQueryData, however this doesn't work if the page is refreshed:
function useWatchlist() {
const { user } = useAuth()
const queryClient = useQueryClient()
const result = useQuery({
queryKey: ['user'],
queryFn: () =>
axios.get(`${baseUrl}/${user.profile_id}/watchlist`).then(response => response.data)
},
{onSuccess: (watchlist) => {
queryClient.setQueryData(['user'], oldUser => {
oldUser.watchlist === watchlist
})
}
})
return {...result, profile: result.data }
}
Should the recommendation/watchlist arrays instead be stored separately using different query keys - ['watchlist']/['recommendations'] or should I attempt to keep the user object structure being returned from the backend?
I would say that yes, you should store them separately. Yet, using relative keys (e.g. ['user', 'watchlist'] and ['user', 'recommendations']) as explained here under Structure:
Structure your Query Keys from most generic to most specific, with as many levels of granularity as you see fit in between
So, you can invalidate them both when the user is refetched.
When I store data such as the "watch list", which only changes when the user changes it, I put a staleTime: Infinity and use setQueryData in the onSuccess of the relevant mutation (when a user updates his watch list).
For the "recommendation list", it's different story, as it would be constantly changing by some logic in the backend. So, I would use invalidateQuery whenever the 'user' key is fetched (or expire the cache, if you update the list each certain interval), and populate it again, on the onSuccess for that query.

CloudKit Bad Request on Users Record Update with Web Services API

I added a custom field to the default Users record type in CloudKit, and I'm trying to push a value to that new field.
Here's how my request is structured in Node JS:
var query = {
operations :[{
operationType: 'forceUpdate',
record:{
recordType: 'Users',
fields:{
myCustomField: { value: 'stuff' }
},
recordName: '_abc123'
}
}]
}
I'm getting this response from CloudKit:
records: [{
recordName: '_abc123',
reason: 'invalid id string, id=_abc123',
serverErrorCode: 'BAD_REQUEST'
}]
If I put that same custom field on another, custom Record Type (like if I make my own User (without the "s") type) that also has myCustomField on it, the update works fine. So there must be something special I have to do to update the system Users type.
Does anyone know how to update a field on a Users record with the web services API?

Change uuid to integer id in mongodb - sails.js

so I have switched the sails.js database from localdisk to mongodb server and all my ids changed to a uuid id.i found that normal id is much easier and cleaner. how can i change my ids to be integer ids again?
btw what are the benefits of using uuid? and how can i make an update request with that long id?
{
"name": "Matan",
"id": "544a7968101ca2903974cdc1",
"createdAt": "2014-10-24T16:08:08.052Z",
"updatedAt": "2014-10-24T16:08:08.052Z"
}
It's the "normal" way that MongoDB creates ids, is a combination of timestamp, machine identifier, process id and random values.
From MongoDB site: "Documents stored in a collection require a unique _id field that acts as a primary key. Because ObjectIds are small, most likely unique, and fast to generate"
It's not recommended to change the ids because is your primary key and maybe some other data is related to them.
If you want to have ids like 1,2,3,4,5... you have to setup your own generation and save the id when you create the model:
User.create({_id: 1, name: 'John'});
You can update the same way you do with "short" ids, through the blueprint api:
PUT /user/544a7968101ca2903974cdc1
And submit new the data with a form or via ajax.
Update a value on existing model example:
var postId;
// create a blog post for example
$.ajax({
url: '/post',
method: 'POST', // create a new entry in the db
data: {
title: 'Untitled Post',
text: 'Example blog post'
},
success: function(data){
// data = {id: 'randomGeneratedId', title: 'Untitled Post', text: 'Example blog post'}
postId = data.id;
}
});
// later...
$.ajax({
url: '/post/' + postId,
method: 'PUT', // update this post in the db
data: {
image: 'path/to/image.jpg'
},
success: function(data){
// data = {id: 'randomGeneratedId', image: 'path/to/image.jpg', title: 'Untitled Post', text: 'Example blog post'}
}
});

Mongoose - update after populate (Cast Exception)

I am not able to update my mongoose schema because of a CastERror, which makes sence, but I dont know how to solve it.
Trip Schema:
var TripSchema = new Schema({
name: String,
_users: [{type: Schema.Types.ObjectId, ref: 'User'}]
});
User Schema:
var UserSchema = new Schema({
name: String,
email: String,
});
in my html page i render a trip with the possibility to add new users to this trip, I retrieve the data by calling the findById method on the Schema:
exports.readById = function (request, result) {
Trip.findById(request.params.tripId).populate('_users').exec(function (error, trip) {
if (error) {
console.log('error getting trips');
} else {
console.log('found single trip: ' + trip);
result.json(trip);
}
})
};
this works find. In my ui i can add new users to the trip, here is the code:
var user = new UserService();
user.email = $scope.newMail;
user.$save(function(response){
trip._users.push(user._id);
trip.$update(function (response) {
console.log('OK - user ' + user.email + ' was linked to trip ' + trip.name);
// call for the updated document in database
this.readOne();
})
};
The Problem is that when I update my Schema the existing users in trip are populated, means stored as objects not id on the trip, the new user is stored as ObjectId in trip.
How can I make sure the populated users go back to ObjectId before I update? otherwise the update will fail with a CastError.
see here for error
I've been searching around for a graceful way to handle this without finding a satisfactory solution, or at least one I feel confident is what the mongoosejs folks had in mind when using populate. Nonetheless, here's the route I took:
First, I tried to separate adding to the list from saving. So in your example, move trip._users.push(user._id); out of the $save function. I put actions like this on the client side of things, since I want the UI to show the changes before I persist them.
Second, when adding the user, I kept working with the populated model -- that is, I don't push(user._id) but instead add the full user: push(user). This keeps the _users list consistent, since the ids of other users have already been replaced with their corresponding objects during population.
So now you should be working with a consistent list of populated users. In the server code, just before calling $update, I replace trip._users with a list of ObjectIds. In other words, "un-populate" _users:
user_ids = []
for (var i in trip._users){
/* it might be a good idea to do more validation here if you like, to make
* sure you don't have any naked userIds in this array already, as you would
*/in your original code.
user_ids.push(trip._users[i]._id);
}
trip._users = user_ids;
trip.$update(....
As I read through your example code again, it looks like the user you are adding to the trip might be a new user? I'm not sure if that's just a relic of your simplification for question purposes, but if not, you'll need to save the user first so mongo can assign an ObjectId before you can save the trip.
I have written an function which accepts an array, and in callback returns with an array of ObjectId. To do it asynchronously in NodeJS, I am using async.js. The function is like:
let converter = function(array, callback) {
let idArray;
async.each(array, function(item, itemCallback) {
idArray.push(item._id);
itemCallback();
}, function(err) {
callback(idArray);
})
};
This works totally fine with me, and I hope should work with you as well