Why am I unable to "map" this mongoose collection? - javascript

I am trying to map a collection of user documents in mongoDB. Below is my code.
User.getUsers = function() {
return new Promise(async (resolve, reject) => {
try {
let users = await ValidUser.find()
users.map(function(user) {
return {
username: user.username,
email: user.email
}
})
console.log(users)
resolve(users)
} catch {
reject("404")
}
})
}
This code just logs the original stored data and doesn't "map" the array at all.

The map function of an array returns a new array after applying the passed in mapping function to each element. If you assign it back into the users variable, that should correct the issue as the console.log and Promise resolve call will now be using the newly created array:
users = users.map(function(user) {
return {
username: user.username,
email: user.email
}
})
From MDN:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

Array.map returns a new array. If you want to use map, you'll need to assign the return array to users.
users = users.map(function(user) {
return {
username: user.username,
email: user.email
}
})
The mapping you want to do can also be done through a projection which is when you specify which fields you want to be returned by the database. In mongoose it might look like this:
let users = await ValidUser.find().select({ username: 1, email: 1, _id: 0 })

Related

GraphQL MongoDb: InsertOne is not returning back document object

I am using graphQL to retrieve data and mongoDb to create my user. When I run the signup mutation in apollo i get the error: Cannot return null for non-nullable field User.id.
I console.log(result) and it equals:
{ acknowledged: true, insertedId: new ObjectId("6432djjedh3i2o211i12je") }
This is not what I want returned as the result. I want result to equal the whole collection that was inserted, which is this:
{_id:6432djjedh3i2o211i12je email:"test#gmail.com" password: "$2a$10$ONkOjWbigkD3fWSo9XdweOzLePZM7CkGa0QgfbVLkyWtS10EU9R5uz8e" name:"name"} (from Mongo Atlas)
My whole signUp Mutation for creating a user is:
Mutation: {
signUp: async (_, {input }, { db}) => {
const hashedPassword = bcrypt.hashSync(input.password);
const newUser = {
...input,
password: hashedPassword
}
const result = await db.collection('Users').insertOne(newUser)
console.log(result);
//result gets reassigned as user
const user = result
return {
user,
token: 'token'
}
}
}
update tried console.log(result.ops[0]) instead but didnt work.

Mongoose: save() is not a function when using find() and atributing value to variable

This is the basic structure of the Schema I am working with using mongoose:
const User = {
uid: {
type: String
},
routes: {
type: Array
}
}
In my application there is a POST to /route, in which uid and a new route are provided as "body parameters". In order to add to the routes array, I wrote a code similar to this (the only diference is that I check if the route already exists):
var user = await User.find({uid: uid}) // user is found, as expected
user[0].routes.push(route //parameter)
user.save()
When a POST request is made, though, it throws an error:
TypeError: user.save is not a function
What am I doing wrong?
user in your code is an array of documents
so you'll have mongo documents inside that array
you can't do array.save, you've to do document.save
await user[0].save()
var user = await User.find({uid: uid}) // user is found, as expected
if (user && user.length) {
user[0].routes.push(route //parameter)
await user[0].save(); // save the 1st element of the object
}
if your query returns only 1 record better use https://mongoosejs.com/docs/api.html#model_Model.findOne
var user = await User.findOne({uid: uid}) // user is found, as expected
if (user) {
user.routes.push(route //parameter)
await user.save(); // save the 1st element of the object
}
if you need to find only one specific user you should use findOne function instead
User.findOne({uid: uid})
.then(
(user) => {
user[0].routes.push(route //parameter);
user.save();
},
(err) => {
console.error(err);
}
)
I think bulkSave() can be what you're looking for:
var user = await User.find({uid: uid}
enter code user[0].routes.push(route //parameter)
await User.bulkSave(user)

.map returns an array of empty objects after getting data with Mongoose

I have a problem when i want an array of collections returned back to me using Mongoose. The problem is that the .map method in the code returns an array of empty objects, but if I log the objects individually in the .map everything is fine. Why is this happening?
const patients = doctor.patients.map(async patient => {
try {
const patientObj = await Patient.findOne({ username: patient });
patient = patientObj;
patient.jwt = undefined;
patient.__v = undefined;
console.log(patient); // This works just fine, logs the object the right way
return patient;
} catch (err) {
console.log(err);
}
});
console.log(patients); // This logs [{}, {}, {}]
I guess you want to have an array of patients which are related to one doctor. Try this solution.
Patient.find({
username: { $in: doctor.patients }
}, (err: any, patients) => {
console.log("patients " + patients)
})
In your Patient model add (select: false), so you do not have to set every field to undefined https://mongoosejs.com/docs/api.html#schematype_SchemaType-select

push array in const inside .then

I'm trying to push a value inside a const but its in a .then and it's not working do you know how can I do that ?
I get a value in my console.log(newResult) in my if but the data is not pushed in my const newResult in the return
res.status(200).json(newResult);
.then(function (friends) {
if (friends) {
const newResult = [];
friends.forEach((r) => {
if (r.UserID == userFound.id) {
models.User.findOne({
where: {
id: r.idFriend
}
})
.then(function(userFound) {
newResult.push({
id: r.id,
user: {
id: r.User.id,
email: userFound.email,
username: userFound.username
}
});
console.log(newResult)
})
} else
newResult.push({
id: r.id,
user: {
id: r.User.id,
email: r.User.email,
username: r.User.username
}
});
console.log(newResult)
});
res.status(200).json(newResult);
}
}
every test realised return an empty tab when i go in my if condition
It will never work because, you are doing async calls
models.User.findOne inside forEach.
You'll get results on console.log when async call to database for fetching user is complete.
But before this all happens the forEach is done executing and code hits the line res.status(200).json(newResult); and you see no results from your if condition.
Instead of using this approach go for mongoose populate and populate userObject based userID while finding friends this way you won't have to do async call inside the forEach.
Read about mongoose populate at: http://mongoosejs.com/docs/populate.html

Promise all map update array

I'm using bluebird and mongoose, I'm getting an array of users in a previous function. I want to update users to set the property hasCar true or false for each user from my array.
function findCars(users) {
return Promise.all(users.map((user) => {
return Car.count({
_creator: new ObjectId(req.user),
userId: user._id
})
.then((car) => {
user.hasCar = !!car;
return user;
});
}))
.then(console.log);
}
The problem is, in the console.log those users don't have the property hasCar set. I tried different ways with no success.
Found what was wrong, it seems you can't add a property which does not exist in my mongoose model User. To bypass it I did:
let updatedUser = user.toObject();
updatedUser.hasCar = !!car;
return updatedUser;
Thanks everyone
It seems to work as it is. I made some simple changes to fake out Car.count and removed ObjectId, and it works as expected:
const cars = {1: ['car a', 'car b'], 3: ['car c']};
const Car = {
count: (user) => new Promise((resolve, reject) =>
setTimeout(() => resolve(cars[user.userId]), 1000))
};
function findCars(users) {
return Promise.all(users.map((user) =>
Car.count({
userId: user._id
})
.then((car) => {
user.hasCar = !!car;
return user;
})
))
.then(console.log);
}
const users = [{_id: 1}, {_id: 2}, {_id: 3}];
findCars(users);
This returns a Promise, and one second later logs the following to the console:
[{"_id":1,"hasCar":true},{"_id":2,"hasCar":false},{"_id":3,"hasCar":true}]
Note, I originally used the simpler
count: (user) => Promise.resolve(cars[user.userId])
But I wanted to ensure some true async. Neither way had any issues.
You can see this in action on RunKit.

Categories

Resources