Mongoose / MongoDB merging two find queries - javascript

I know this will be a simple answer but I've never had to do more than a single query at a time before!
I have a game item, and I want to return the games a user is part of as a list, it queries first to see if they're host, and then if they're a player. Then taking the result of both of those queries and sorting by createdOn time.
As you'll see, I have it working for the first query for gamePlayers.user, but I need to also be able to query host.user.
Like I said, I know this will have a simple answer but my googling is coming up empty and I'd appreciate any responses!
router.get('/currentgames', passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {};
const userId = req.user.id;
Game.find({"gamePlayers.user": userId})
.limit(10)
.sort({lastUpdated: -1})
.then(games => {
if(!games) {
errors.nousergames = 'You have no games yet';
return res.status(204).json(errors);
}
res.json(games);
})
.catch(err =>
res.status(404).json({ game: 'There are no games'})
);
});

Related

Query while iterating on array

I have Announcements and AnnouncementLikes schema. There is one schema for announcements and other one is for if user liked the specific announcement. My plan is sending announcements with like state to the user that made a request.
So on the below I tried to get like while iterating on announcement list.
const announcements = await AnnouncementModel.paginate(
{},
{
page,
limit,
lean: true
}
)
announcements.docs = announcements.docs.map((annonucement) => ({
...annonucement,
like: (async () => {
const result = await AnnouncementModel.findIfUserLiked(
annonucement.id,
req.userId
)
return result
})()
}))
It is inside of AnnouncementSchema I didnt want to copy all of the schema
static async findIfUserLiked(announcementId: string, userId: string) {
const foundAnnouncementLike = await AnnonucementLikeModel.findOne({
announcementId,
userId
})
return !!foundAnnouncementLike
}
I know that I cant get likes from immediatly invoked function because it returns a promise. So I have to stop iterate somehow and get like before sending to user. So i tried this solution but it didnt work as well
const fullOfPromises = announcements.docs.map((announcement) => announcement.like)
Promise.all(fullOfPromises).then(() => {
res.send(announcements)
})
I am new to mongoose and I dont know how to get user likes in the announcement list.
Thanks in advance

Res value is null in an app.get call done from vue.js front-end to express back-end

I am calling this code from the front-end and confirmed that there is a proper db connection and that the Id value is properly passed, and that there is a corresponding value in the database, but for some reason, res is null. What am I missing?
app.get("/api/walletlogin/user/:userId", (req, res) => {
id = req.params.userId
var query = {_id: id}
db.collection("Users").findOne(query, (err, result) => {
if (result) {
console.log(result.userName)
} else {
console.log('No User')
}
})
Here is the front-end call:
axios.get('/api/walletlogin/user/' + accounts)
.then((response) => {
console.log('Logged in With ' + accounts)
router.push('/account')
})
.catch((errors) => {
console.log('Cannot log in')
})
}).catch((err) => {
console.log(err, 'err!!')
})
You could try to convert your id to an objectID.
var ObjectId = require('mongodb').ObjectId;
var id = ObjectId(req.params.userId);
to search by id, you must use the ObjectID class from the mongodb package. Here is an example invented by me, it does not reflect the real work, but I hope it will become clear on it:
const { ObjectID } = require('mongodb');
const id = '5ee4f69bfa0b960de8aec158'; // in your example is req.params.userId
db.collection('users').findOne({ _id: new ObjectID(id)}, (error, result) => {
if (error) {
throw error;
}
console.log(result);
})
I am adding the details of the issue initially encountered in case someone else would experience it in the future. The value that is passed from the front-end is a cryptocurrency address. For some reason, some of the characters passed were upper-case, while the same address had been stored in the database with these same characters as lower case. Thus, one needs to add code to make sure that the case of the letters found in the respective addresses is ignored.
J

How to use forEach when iterating over collection objects MongoDB?

please suggest me how to make a selection from database comparing the ID in the collection with each element of the array?
Here is the code that unfortunately returns an empty array:
index(req, res) {
Room.find({_id: req.user.rooms.forEach((item)=>{
return item;
})
})
.then((rooms) => {
console.log(rooms)
res.send(rooms)
}
)
.catch(err => res.status(400).json(err));
}
req.user.rooms - each item of this array is ID, that I want to compare with what is in the collection Room.
It's pretty straight-forward in their docs for how to query items in a list.
Your code should look something like this:
index(req, res) {
// Additional validation should be done to make sure that req.user.rooms
// is an array with length > 0. I'll leave that for you to do.
const rooms = req.user.rooms;
Room.find({ _id: rooms})
.then((rooms) => {
console.log(rooms)
res.send(rooms)
})
.catch(err => res.status(400).json(err));
}
Going beyond that, you should really not be doing DB queries from your controller; it's not a good architectural practice This is how it could look in your node service
roomController.js
const RoomService = require("/path/to/services/directory"); // Let services contain all business logic. Don't give them anything related to your web server framework
async index(req, res) {
// Additional validation should be done to make sure that req.user.rooms
// is an array with length > 0. I'll leave that for you to do.
try {
const rooms = await RoomService.retrieveById(req.user.rooms);
res.send( { success: true, data: rooms } ); // We send back the result when we get one
} catch ( err ) {
// We respond to the client with our error, ideally you'll log it too
res.status( err.statusCode ).send( { success: false, error: err } );
}
}
RoomService.js
const Room = require("/path/to/your/model");
module.exports = {
retrieveById: async function(ids) {
try {
return await Room.find({ _id: ids}); // Typically this would be abstracted to a DB layer. but putting it here for brevity
} catch( err ) {
throw new Error( err ); // This is caught in our controller, which we send to client
}
}
};

Post Multiple Objects Inside Express Route

I would like to post multiple objects to my mongo database inside of an express route. Currently, everything is working fine when I do it as a single object (ie ONE casino), please see below, but instead of doing this a million times over, can someone help me do it as one giant data dump so I can post ALL my casinos?
Here is my route that works fine for posting a single object:
router.post('/post', async (req, res) => {
console.log(req.body);
const casinoD = new Casino({
casino: req.body.casino,
table_and_other: req.body.table_and_other,
poker: req.body.poker,
slot_machines: req.body.slot_machines,
total_gaming_win: req.body.total_gaming_win,
year: req.body.year,
month: req.body.month,
combined_date: req.body.combined_date
})
try {
const newCasino = await casinoD.save()
res.status(201).json(newCasino)
} catch (err) {
res.status(400).json({ message: err.message})
}
})
I also understand mongoimport is a better way to do this - however that had its own issues in of itself.
Thanks
Like #JDunken said, you can iterate over the POST body as an array and insert in bulk. You'll want to use
insertMany for speed. To insert millions of records, you will probably want to put a sane limit on the number of records per request, and send API requests in batches. Validation is optional, as Mongoose will run validation according to the schema. It depends on how you want to handle validation errors. Make sure to read up on the ordered and rawResult options for that as well.
router.post('/post', async (req, res) => {
// you should sanity check that req.body is an array first, depending on how robust you want error handling to be
const casinos = req.body.filter(input => isValid(input));
try {
const insertedCasinos = await CasinoModel.insertMany(casinos, { ordered: false });
res.status(201).json(insertedCasinos)
} catch (err) {
res.status(400).json({ message: err.message})
}
})
const isValid(input) {
let valid = true;
// implement input validation
return valid;
}

Twilio SMS message keeps resending the same message

So I'm trying to send notifications to users phones with Twilio, however, the same message is sent three times. I do have three phone numbers hardcoded into an array (providerNumbers) so I think it's looping through three times because of this.
What I'm trying to do is eventually populate the phone numbers array from user-provided phone numbers they store on Firebase for each user. So a different user will receive the same notification to let them know to visit the website.
Here's my Node.js code:
var providerNumbers = ['number1', 'number2', 'number3'];
var body = "..."
app.get('/testtwilio', function(req, res){
Promise.all(
providerNumbers.map(number => {
return twilio.messages.create({
to: number,
from: '+15704058347',
body: body
});
})
).then(messages => {
console.log('Messages Sent!');
}).catch(err => console.error(err));
});
Anyone know how I can prevent the message sending three times to all the users?
There is nothing wrong with the code you posted.
.map calls the callback function once for each element in your providerNumbers array.
The callback function sends only one message when executed.
You can verify this if you log the index with something like this:
app.get('/testtwilio', function(req, res){
Promise.all(
providerNumbers.map((number, index) => {
console.log(index);
return twilio.messages.create({
to: number,
from: '+15704058347',
body: body
});
})
).then(messages => {
console.log('Messages Sent!');
}).catch(err => console.error(err));
});
In conclusion, something must be hitting your endpoint '/testtwilio' three times.
I hope this helps.
Your example seems to work, try checking the logs to see if multiple requests are being made to the same endpoint. A more concise method of mapping an array of primitives to promises would be using Promise.map. Reducing the usage of complex unit structures reduces the number of procedures your code has to perform, makes it easier to debug and to rule out false positives.
const providerNumbers = ['number1', 'number2', 'number3']
const from = '+15704058347'
const body = "..."
app.get('/testtwilio', (req, res, next) => {
Promise.map(
providerNumbers,
to => twilio.messages.create({to, from, body})
).then(res => {
console.log('Messages sent')
res.json({success: true})
}).catch(next)
})
I solved the problem by changing app.get to app.post.

Categories