Find data by two values in mongoose - node.js

Structure is
{
id : 12345,
userIDs : [ "1", "2", "3"]
}
How to write query in nodejs to find userId is present in document or not on the based on id? So we have to pass two values in query first is ID and second is userId, am I correct?

Structure.findOne( {'id' : id, "userIDs" : userId },
'-_id' , function (err, u) {
if(!err) {
//callback
} else {
// callback
}
}
u return null if not match otherwise it return whole document.

Related

mongoose #set and $unset conditional

in my project i want to allow optional fields in a document, but i don't want to save any null values, i.e. i want to remove any field with null.
the values can be changed during run time.
i found how i can make a field null if the user didn't send data to update it (all the fields that the user send empty values for should get deleted).
if the user send firstName/lastName as an empty string in the form i want to remove them.
await Employee.findOneAndUpdate({ _id: employee._id },
{$set: {firstName: null, lastName: null, ...req.body.newEmployee}}, { new: true, upsert: false });
i tried to add an $unset option but i got an error
MongoError: Updating the path 'firstName' would create a conflict at 'firstName'
i thought about deleting it after the update (as a second command) but i can't find a way to tell/get all the null fields of the employee, and i can't get a fixed values to check because there are many combination for the null/not null values, especially if there will be more fields in the future.
i.e. i cant tell if (FN: null, LN: null or FN: "johny", LN: null etc..)
Update : In case if you need to keep some fields as is in existing document then try this, with this new code only the fields coming in request will either be updated or deleted doesn't alter other existing fields in document :
Your node.js code :
let removeObj = {}
Object.entries(req.body).forEach(([key, val]) => {
if (!val) { delete req[body][key]; removeObj[key] = '' };
})
let bulkArr = []
if (req.body) bulkArr.push({
updateOne: {
"filter": { "_id": ObjectId("5e02da86400289966e8ffa4f") },
"update": { $set: req.body }
}
})
if (Object.entries(removeObj).length > 0 && removeObj.constructor === Object) bulkArr.push({
updateOne: {
"filter": { "_id": ObjectId("5e02da86400289966e8ffa4f") },
"update": { $unset: removeObj }
}
})
// For mongoDB4.2 removeObj has to be an array of strings(field names)
let removeObj = []
Object.entries(req.body).forEach(([key, val]) => {
if (!val) { delete req[body][key]; removeObj.push(key) };
})
// After this, Similar to above you need to write code to exclude empty removeObj for 4.2 as well.
Query :: On mongoDB version >= 3.2 to < 4.2 .bulkWrite():
db.yourCollectionName.bulkWrite(bulkArr)
Query :: From mongoDB version 4.2 .updateOne accepts aggregation pipeline :
db.yourCollectionName.updateOne(
{ "_id": ObjectId("5e02da86400289966e8ffa4f") },
[
{
$set: req.body
},
{ $unset: removeObj }
]
)
Old Answer : You need to try .findOneAndReplace() , if you want entire doc to be replaced :
db.yourCollectionName.findOneAndReplace({_id: ObjectId("5e02da86400289966e8ffa4f")},inputObj, {returnNewDocument:true})
Your collection :
{
"_id" : ObjectId("5e02da86400289966e8ffa4f"),
"firstName" : "noName",
"lastName": 'noName',
"value" : 1.0,
"empDept": 'general',
"password":'something'
}
Your request object is like :
req.body = {
firstName: 'firstName',
lastName: null,
value : 1.0,
empDept: ''
}
your node.js code (Removes all falsy values ( "", 0, false, null, undefined )) :
let inputObj = Object.entries(req.body).reduce((a,[k,v]) => (v ? {...a, [k]:v} : a), {})
your collection after operation :
{
"_id" : ObjectId("5e02da86400289966e8ffa4f"),
"firstName" : "firstName",
"value" : 1.0,
}
your collection after operation as per updated answer :
{
"_id" : ObjectId("5e02da86400289966e8ffa4f"),
"firstName" : "firstName",
"value" : 1.0,
"password":'something'
}

Create Rating if Not Rated Yet, Update User Rating if Rating Exists

I am creating a user experience where a user will be able to rate items from different vendors. My initial thought is for each User schema to have an array which stores all the items that the user has rated. The rated item would include the unique vendor item ID and a numerical rating value.
User Model
const userSchema = new mongoose.Schema({
...
userType: String,
ratedItems: Array,
...
});
Controller
exports.postUpdateRatedItem = (req, res, next) => {
User.findById(req.user.id, (err, user) => {
if (err) { return next(err); }
user.update(
{ $push: {ratedItems : {
vendorItem : req.body.itemID,
rating : req.body.rating
}}},
function (err) {
res.send(200);
});
});
}
Current Output
{
"_id" : ObjectId("5c91869a71ece20551fd6aed"),
"userType" : "participant",
"ratedItems" : [
{ "vendorItem" : "5c9bdd524a0dfa753e08a0a4", "rating" : "3" },
{ "vendorItem" : "5c9bdd524a0dfa753e08a0a4", "rating" : "6" }
]
}
This approach works great in adding new object to the array, but only adds and does not update. Instead, every time a user updates a rating, a new object is added to the array. What approach would allow to check for the unique vendorItem id? How do I go about checking the user rated items? If found, update the rating value, if not found, push to the array.
Thank you in advance, still learning MongoDB/Mongoose.
Edit
Below is what I expect the outcome. For each object in the array, the 'rating' is updated when the user changes the rating. The ratedItems array will eventually have many many vendorItem with unique IDs and ratings.
Expected Output
{
"_id" : ObjectId("5c91869a71ece20551fd6aed"),
"userType" : "participant",
"ratedItems" : [
{ "vendorItem" : "5c9bdd524a0dfa753e08a0a4", "rating" : "6" },
// additional rated items all with unique IDs
{ "vendorItem" : "5c9bcc14d5161c38a4581e28", "rating" : "2" },
{ "vendorItem" : "5c9407d143cd0f20d758acdb", "rating" : "11" }
]
}
It sounds like you are looking for "upsert" functionality. The Mongoose model API provides findByIdAndUpdate and other similar methods for this.
Make sure you set the new and upsert options to true. This will create the object if it doesn't exist and return the modified document if it is updated.
Your use case would look something like this:
const update = {
$push: {
ratedItems: {
vendorItem: req.body.itemID,
rating: req.body.rating
}
}
};
const options = {'new': true, upsert: true};
User.findByIdAndUpdate(req.user.id, update, options, function(err, user) {
// ...
});

Using aggregations to group elements of my array which are present in mongoDB but returning nothing?

Hello all i have an array of items now i want to know which of them are present in mongoDB now for that i read that i should use aggregations now i am using aggregations but it is not returning anything can anyone please point out what am i doing wrong below is my query given
userfavouritemodel.aggregate([
{ "$match": { "offers": {"$in": my_array}, "mobile_no":"1234567890" } },
{ $unwind: "$offers" },
{ "$group" : { "_id":"$_id","matched_elements":{ "$addToSet": "$offers" }}}
], function (err, result) {
if (err) {
console.log(err);
return;
}
console.log('user favourites');
console.log(result);
});
UPDATE- Example of documents in my database
{ "_id" : "566d6add9384223014ebcf43" , "mobile_no" : "1234567890" , "total_offers" : 4 , "offers" : [ "565ae5d8fff110dc18718b7c" , "565ae479fff110dc18718b7a" , "565ae479fff110dc18718b7a" , "5644a9339bf660501f15254e"]}
Here you go, this will return the offers that matches the mobile number and the offers within the array:
db.collection.aggregate([
{$match:{mobile_no:"1234567890"}},
{$project:{_id:0, offers:1}},
{$unwind:"$offers"},
{$match:{offers:{$in:["565ae479fff110dc18718b7a", "565ae5d8fff110dc18718b7c"]}}}]);

Delete item from MongoDB with Nodejs

I'm trying to delete a user id from all collections that have a reference to it. I'm bringing a user id across from the form and want to remove every reference to it in every business collection. I know the below query doesn't work but it shows my current approach.
db.collection('business', function (err, allBus){
allBus.update({}, { $pull: {followers: { userID } } } );
});
Here is my data, any ideas?
{
"_id" : ObjectId("55355d0ab063708c0b73809e"),
"address" : "Donegal",
"businessName" : "burkes shoes",
"email" : "info#burkes.ie",
"followers" : [
ObjectId("55300f5208224af428d1beaf"),
ObjectId("553129666252d2fc0a4634e4")
],
"gpsLat" : "55.1763595",
"gpsLong" : "-7.7923",
"homeDomain" : "www.burkes.ie",
"imgpath" : "\\images\\uploads\\57461Burkes_logo_1429560586607.jpg",
"password" : "1",
"role" : "business"
}
If userID is a string you will need to cast it first to ObjectID before using it in your query. Something like this should do the magic:
var ObjectID = require("mongodb").ObjectID,
userID = new ObjectId("55300f5208224af428d1beaf");
/*
if userID is a string then this will work
var userID = new ObjectId(userID);
*/
db.business.update(
{"followers": userID},
{
"$pull": { "followers": userID }
},
{ multi: true }
);
The query above will have better performance than an update without a query as it first filters documents that have in their followers array an element with the userID value and then updates the matched documents by pulling the ObjectID value from the array.

nodejs/mongodb - reading out one specific element

I want to read out one specific element out of mongodb
db.collection('profiles', function(err, collection) {
collection.findOne({'email': mail}, function(err, item) {
this reads the whole entry
for example:
{
"email" : "asdd#asd.de",
"password" : "asd",
"_id" : ObjectId("51c8790f912501e403000001")
}
how can i read out only one of those elements
for example password
{
"password" : "asd"
}
collection.findOne({'email': mail}, {password: 1, _id: 0}, function(err, item) {
}
The second argument to find/findOne is the fields to select(projection).
{_id: 0} is explicitly required because by default _ids are always returned.

Resources