MongoDB find documents but exclude those without the field - javascript

I'm trying to query a collection and sort it by a field that doesnt exist in every record. For example im calling this:
exports.getProductPriceByLosers = (req,res) => {
Market.find()
.sort({ "analytics.one_day_change": 1 })
.select('analytics.one_day_change name')
.limit(10)
.exec((err, data) => {
if (err){
return res.status(400).json({
error: 'No products found'
})
}
res.json(data)
})
}
However the field 'one_day_change' doesn't exist on every record so the result im getting is about 20 products first without that field, and then it returns the prodcuts i do need with the correct sort. Is there a way i can tell mongo not to return those documents i dont need / dont have the data i need?
Thanks!! x

You can use $exists: true to get only documents where that field exists.
exports.getProductPriceByLosers = (req,res) => {
Market.find({"analytics.one_day_change":{ "$exists": true}})
.sort({ "analytics.one_day_change": 1 })
.select('analytics.one_day_change name')
.limit(10)
.exec((err, data) => {
// ...
})
}
Check this example

Related

How to check if key exists on mongoose document?

I have a User Model and recently added some key to it. This means that existing users will not have this key initially and new users do. Now I have a route where I want to check if the particular key exists on the user object so that I can add it if it returns false.
This is my route currently:
router.post("/new-application", verifyUser, (req, res) => {
const { application } = req.body;
User.findById(req.userId)
.then((user) => {
if (user.hasOwnProperty("applications")) {
console.log("has applications");
} else {
console.log("has not applications");
user["applications"] = initialApplications;
}
user.save().then((updatedUser) => {
// console.log(updatedUser);
});
})
.catch((err) => {
console.log("err fetching user: ", err);
res.end();
});
});
The problem is that if (user.hasOwnProperty("applications")) always returns false even after I added it to the user. I also tried if("applications" in user). That also does not work.
So how can I check if a key or field exists on a Mongoose object.
A simple way of checking if the field exists or not can be done by $exist.
router.post("/new-application", verifyUser, (req, res) => {
const { application } = req.body;
User.findById({$and: [{_id: req.userId}, {applications: {$exists:false}}]})
.then((user) => {
// it will return the user only when
// applications doesn't exist
})
.catch((err) => {
console.log("err fetching user: ", err);
res.end();
});
});
Note: the reason your old user doesn't show the applications is they don't have it when you saved them and changing the model now won't add this property to old models. So, we can use the $exists operator to check it.

Creating new mongoose sub-doc and appending to existing parent doc

I'm building a website with a database using NodeJS, MongoDB, Express, Mongoose etc.
I have two schema set up: Events and a sub-doc schema Categories (among others).
The function pulls in array which contains the data needed to create several categories (this bit works) as well as the Event ID appended to the end.
The first few bits below just grab that ID, then remove it from the array (probably a better way to do this, but again, it works).
As mentioned above, the Categories then create correctly (and even do validation), which is amazing, BUT...
They don't get appended to the Event doc. The doc updates the "categories" field to an applicable number of "null" values, but I cannot for the life of me get it to actually take the IDs of the newly created categories.
I nabbed (and adjusted) the below code from somewhere, so this is where I'm at...
exports.addCategories = catchAsync(async (req, res, next) => {
const categories = req.body;
const length = categories.length;
const eventID = categories[length - 1].eventId;
categories.pop();
Event.findOne({ _id: eventID }, (err, event) => {
if (err) return res.status(400).send(err);
if (!event)
return res.status(400).send(new Error("Could not find that event"));
Category.create(categories, (err, category) => {
if (err) return res.status(400).send(err);
event.categories.push(category._id);
event.save((err) => {
if (err) return res.status(400).send(err);
res.status(200).json(category);
});
});
});
});
Currently the mongoose debug output is showing the following (which confirms that MOST of it is working, but the IDs just aren't being pulled correctly):
> Mongoose: events.updateOne({ _id: ObjectId("614bc221bc067e62e0790875")}, { '$push': { categories: { '$each': [ undefined ] } }, '$inc': { __v: 1 }}, { session: undefined })
Nevermind! I realised that "category" was still an array, rather than an element of the categories array as I'd assumed.
So I replaced that section with this, and now... it works!
Category.create(categories, (err, categories) => {
if (err) return res.status(400).send(err);
categories.forEach((category) => {
event.categories.push(category._id);
});
event.save((err) => {
if (err) return res.status(400).send(err);
});
});

How to get data with just inserted data with Sequelize in PostgreSql?

I want to get updated table values after I add user to my "WOD" table. For instance, I have 2 users in my WOD table and after I add third user , I want to return a response to client with I have just inserted data (third guy). But now , I can only return first 2 users because I can not take updated values. Of course I can make another query to get updated table values after I insert, but is there any better solution ? Here is my codes;
const addUser = async (req, res) => {
try {
const { userId, wodId } = req.body;
if (!userId || !wodId) {
res.status(400).send({ status: false, message: 'need userId and wodId' });
}
const wod = await Wod.findByPk(wodId, {
include: [
{
model: User,
as: 'Participants',
through: { attributes: [] }
}
]
});
//check capacity if full.
if (wod.Participants.length >= wod.capacity) {
res
.status(403)
.send({ status: false, message: 'Capacity of this class is full!' });
}
const result = await wod.addParticipants(userId);
res.status(201).json({ status: !!result, wod });
} catch (error) {
res.status(500).send({ status: result, message: error.message });
console.log(error.message);
}
};
As a result of many-to-many association sequelize.sync will generate some functions for us. You are used addParticipants function and this returns an array that added to the assocation(userwod) table.
In this array you will find some id fields(join table fields) because you just run like this INSERT INTO 'user_wods' ('user_id''wod_id') VALUES (2,1). If you want to return the added user's information then you should run a SELECT * FROM 'user' WHERE 'id'=2.
You must call reload function for fetch the third guy.
await wod.reload()

Elegant way to update many properties with mongoose

I have a model with 7 properties and want to update them all when there is an edit request from front-end. Is there any elegant way to do so, or do I have to type all of them manually like in my code bellow (whitch by the way works fine for me, but looks really ugly).
exports.saveDish = (req, res, next) => {
const {
name,
description,
price,
category,
vegetarian,
hot,
menuPosition,
} = req.body;
Dish.findById(req.body._id)
.then(oldDish => {
if (oldDish) {
oldDish.name = name;
oldDish.description = description;
oldDish.price = price;
oldDish.category = category;
oldDish.vegetarian = vegetarian;
oldDish.hot = hot;
oldDish.menuPosition = menuPosition;
oldDish.save();
return res.status(204).json({ message: 'Dish data properly updated' });
}
const newDish = new Dish(req.body);
newDish.save();
return res.status(201).json({ message: 'New dish properly saved' });
})
.catch(err => console.log(err));
};
This will update an existing record and return the updated value. If no matching record is found, it will return a falsey value to the callback or promise (can't remember if it's null or something else).
Dish.findByIdAndUpdate(req.body._id, updates, {new: true}, cb)
You can try something like this :
exports.saveDish = (req, res, next) => {
/**
*
* upsert: true --> helps to insert new document if no matching doc exists
* new: true --> returns new document in output
* rawResult: true --> helps to find out whether update or insert operation is done
*
* Dish is a mongoose schema where findByIdAndUpdate is only from mongoose,
* which internally converts a string from it's first parameter into {_id : ObjectId('req.body._id')}, also uses $set operation on req.body
*
* Print data to check what's being returned, you might see entire document(data.value) being returned with some other information
*
* */
Dish.findByIdAndUpdate(req.body._id, req.body, { upsert: true, new: true, rawResult: true }, (err, data) => {
if (err) { console.log(err); res.status(200).json({ message: 'Operation Failed' }) }
if (data.lastErrorObject.updatedExisting) return res.status(204).json({ message: 'Dish data properly updated' });
return res.status(201).json({ message: 'New dish properly saved' });
})
};
Here you're updating existing document (adding new fields or updating the existing fields w.r.t. what's there is req.body) or inserting an entire new document if no matching _id is found in database, this way you avoid multiple DB calls. Here I've made it in callbacks, but earlier I've actually done it in async await, it does work either way, this should work for all of your cases listed above !!
Ref : Mongoose findByIdAndUpdate
#EddieDean, your way worked almost fine, it turns out that you have to pass any id to findByIdAndUpdate() method, so I edited it a little bit to work with unique, new dishes too.
Working code just in case:
exports.saveDish = (req, res, next) => {
if (req.body._id) {
Dish.findByIdAndUpdate(
{ _id: req.body._id },
{ ...req.body },
{ useFindAndModify: false }
)
.then(oldDish => {
if (oldDish) {
oldDish.save();
return res
.status(204)
.json({ message: 'Dish data properly updated' });
}
})
.catch(err => console.log(err));
} else {
const newDish = new Dish(req.body);
newDish
.save()
.then(result => {
return res.status(201).json({ message: 'New dish properly saved' });
})
.catch(err => console.log(err));
}
};

How to add conditional checks over ORM (sequelizejs) queries?

Suppose i have a table gameData {gameId, currentBoardLayout}, a get request like www.chess.com/asd123 is sent over to the server, where asd123 is my game id, I need to catch this id (asd123 which is my gameId) and check for it in my table (gameData) and implement the following logic :
srv.get('/:id', (req, res) => {
if ( gameData.findAll({where: {gameId: req.params.id} )
{ // Game room found
return currentBoardLayout
}
else
{ error : Invalid game id }
})
How can I achieve this?
Thanks
You can use Sequelize's findById method.
srv.get('/:id', (req, res) => {
gameData.findById(req.params.id)
.then(result => {
res.send(result)
})
.catch(() => {
res.send({
error: 'Could not find ID'
})
})
})
Here's what is happening:
Sequelize's findById method will return a promise. If it successful, you will get your item from the database back. If the item cannot be found, the catch method will fire.
res.send is Express' way of sending data back to the client.
It is worth checking out the Sequelize docs:
Using models
Querying

Categories

Resources