Mongoose - search a document and update some fields of a subdocument - javascript

I'm quite new with Mongoose, I'm trying to get familiar with it,but the poor documentation doesn't help (no search, no list of functions,..).
I have a document that represents a Company, and subdocuments that represents the users:
{
"_id": "57ffa47f5b70f90831212348",
"name": "mycompany",
"address": "...",
"phone": "...",
"users": [
{
"_id": "57ffa47f5b70f90831212347",
"username": "alpha",
"name": "myname",
"surname": "mysurname",
"password": "..."
}
]
}
I want to find a particular subdocument and update just some fields (name,surname, password,...) that are passed from frontend.
I receive req.body that contains the fields edited (i.e. req.body.name) and req.user that contains the user logged:
"company_shortname": "CMPNY",
"company_id": "57ffa47f5b70f90831212348",
"user": {
"id_access_level": 0,
"surname": "ltd",
"name": "mycompany",
"username": "mycompanyusername",
"_id": "57ffa47f5b70f90831212347",
"password": "..."
}
}
what I want to obtain is find the subdoc edited (the company that contains this subdoc will be always the same of the user logged in), update data passed, and save.
Using this answer, I tried:
Company.find({'_id': req.user.company_id}).select('name').exec(
function(err, company) {
if (err) res.status(500).send(err);
var partialUpdate = req.body;
var set = {};
for (var field in partialUpdate) {
set['users.$.' + field] = partialUpdate[field];
}
company.update({_id: req.user._id, "users._id": req.body._id},
{$set: set},
function(err, numAffected) {
console.log('Number of users edited: ' +JSON.stringify(numAffected,null,4));
});
});
but I cannot get it to work.. any ideas?

I solved using this query:
//saving in 'set' the fields to be edited
var partialUpdate = req.body;
var set = {};
for (var field in partialUpdate) {
set['users.$.' + field] = partialUpdate[field];
}
//find the company,then the subdoc, then set the fields with 'set'
Company.findOneAndUpdate({
'_id': req.user.company_id, "users._id" : req.body._id},
{$set: set},
function(err, company) {
//the company status after the update
console.log('company updated: ' +JSON.stringify(company,null,4));
});

Related

can I use orderBychild("person").limitToLast(1) to get the last record which has the property "person"?

My application sends the messages which have variable properties to firebase database.
some messages only have 2 properties:
{
"time": "xxxx"
"location": "xxxxxx"
}
others have 3 properties:
{
"time": "xxxx"
"location": "xxxxxx"
"person": "xxxx"
}
The messages are sent without a specific order.
I want to get the last message which has the property "person", my javascript code is like:
fireBaseRef.orderByChild("person").limitToLast(1).once("value").then((snapshot)=> {
var temp = snapshot.val();
for (var tempkey in temp) {
console.log("person is:" + temp[tempkey].person;
}
})
Is my code correct? I did some tests, it doesn't work well.

Mongoose: Updating a nested array inside of an array

I am trying to figure out how to update a nested array that is within an array with Mongoose. In my User collection, I have a customer array that contains customer info, along with a nested fleet array that holds the customer's fleet equipment. I am trying to update the fleet array via a PUT request, but am having difficulties.
I partially think it is not possible to update a nested array within an array like this, and maybe I should create a separate Schema for the customer and fleet. Anyways, here is what my User Schema looks like currently:
{
"username": "xps_maint",
"password": "0000",
"registerDate": "2018-10-24T13:37:12.093Z",
"_id": "5bd07612d63de74932734d92",
"customer": [
{
"name": "Freight Service ",
"email": "info#fsllc.com",
"dotInterval": "90 days",
"fleet": [
{
"unitType": "Box Truck",
"unitNumber": "BT-61318",
"vinNumber": "1XXXYYYUUUZZ3222",
"_id": "5bd0aef1e2abd64b12e0ab42"
},
{
"unitType": "Cargo Van",
"unitNumber": CV-78453",
"vinNumber": "4ZZYYYTTUZZ3JK2",
"_id": "5bd0aef1e2arg64b15e0ab43"
}
],
"_id": "5bd0821f79f9454b06b2c2bf"
}
],
"__v": 0
}
Here is my PUT route to update the fleet array:
router.put('/customers/fleet/:equipmentid', customer_controller.customer_update_fleet);
And finally here is the what the fleet update controller looks like:
exports.customer_update_fleet = (req, res) => {
const { body, params } = req;
const { unitType, unitNumber, vinNumber } = body;
const { equipmentid } = params;
const updatedEquipment =
{
unitType: unitType,
unitNumber: unitNumber,
vinNumber: vinNumber,
}
User.updateOne({ 'customer.$.fleet': { _id: equipmentid }}, { $set: { 'customer.$.fleet': { updatedEquipment} } }, (err) => {
if (err)
throw err;
else
res.send('Success!!');
});
}
I thought this might of worked, because I have a similar PUT route that updates just the customer array in the User Schema via Model.updateOne(). However this does not seem to work the same way when trying to go deeper into the nested fleet array within each customer.
I may be approaching this all wrong, so I am all ears on a better way to model the User Schema. I do partially think that it is not too good to have arrays nested deep in Schemas like this, they seem like a pain to update. Thanks in advance for reading!

Set data in array of array using mongoose

I've got such User object:
{
"_id": "584d91ff6c751769fab91be5",
"username": "svit",
"name": "Ilya",
"role": "user",
"authData": [
{
"fb": {
"access_token": "susdfg",
"expiration_date": 1,
"id": "1187410264678321"
}
}
],
"__v": 9,
"currentToken": "9735f44f1c4371f143747ff670b0076148053f391ab866bafab7c6eaf47d295b"
}
I am interested in updating User.authData.fb. I tried that:
var curUser = userModel.findOne({_id: user._id}, function(err, curUser){
curUser['authData'][socialType] = {
access_token: socialToken,
expiration_date: 173249700 //TODO: normal date
};
curUser.set('currentToken', tokenName);
curUser.markModified('authData');
curUser.save();
});
But that does just nothing. It modifies currentToken, but not authData.
Also, I tried curUser.set('authData.fb.expiration_date", 173249700)
That does not works too.
I really need your help!
Best regards,
Ilya
You can loop through the 'authData' array and modify whatever values you may like. I am assuming authData is a array of socialTypes and it has an attribute name to indentify.
example:
var curUser = userModel.findOne({_id: user._id}, function(err, curUser){
curUser.authData.map(socialType => {
// Select the type of socialAuth you want to modify
if(socialType.name === 'fb') {
access_token: socialToken,
expiration_date: 173249700 //TODO: normal date
}
})
curUser.set('currentToken', tokenName);
curUser.markModified('authData');
curUser.save();
});

How to write find and update query in express.js?

I am using REST API(express.js and mongodb) and trying to update my document but it's not working. I don't know what is the error but can someone help me out to move forward? I have added my route and controller
Routes:
app.route('/articleupdation')
.post(article.updatearticle);
Controller:
exports.updatearticle = function(req, res) {
Article.findOne({
Username: 'xx',
Email: 'xx#gmail.com',
Info: 'Deactivate',
}, function(err, article) {
if (!err && article) {
article.Info = 'Active';
article.save(function(err) {
if (err) {
console.log('not working');
} else {
console.log('working');
}
});
} else {
console.log('Condtion not matched ');
console.log(err);
}
});
};
Data stored like this
{
"_id": {
"$oid": "5799995943d643600fabd6b7"
},
"Username": "xx",
"Email": "xx#gmail.com",
"Info": "Deactivate",
"Description": "aajdjdjddjdkjddjdjdhdj",
}
Here is what I am trying to achieve; if Username, Email, Info are matched I need to update article.Info = 'Active'; but this is not working, can someone help me out please?
From the looks of it, your query is not matching any documents in the collection hence the statement branch which does the update is not being reached, just the else statement as the returned article is null. You can test this by running the raw query in mongo shell on the underlying collection i.e.
db.articles.findOne({
"Username": "xx",
"Email": "xx#gmail.com",
"Info": "Deactivate"
})
and see if that returns any matching document. If not, check the Info field from the document returned in this query
db.articles.findOne({
"Username": "xx",
"Email": "xx#gmail.com"
})
The best way to go about this within an atomic update that does not require two requests to the server (i.e. one to query the document and the other to write the changes to the server) is to use the findOneAndUpdate api. This will issue a mongodb findAndModify update command which modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use the new option.
Thus your refactored code could follow this pattern:
exports.updatearticle = function(req, res) {
Article.findOneAndUpdate(
{ "Username": req.body.username, "Email": req.body.email, "Info": "Deactivate" },
{ "$set": { "Info": "Active" } },
{ "new": true },
function (err, doc) {
if (err) { // err: any errors that occurred
console.log(err);
} else { // doc: the document before updates are applied if `new: false`
console.log(doc); // , the document returned after updates if `new true`
console.log(doc.Info);
}
}
);
};

MongoDB Query: Exclude objects from child array?

I'm working on a simple login system for my NodeJS application. For this I have created a structure where one object, a "corporation", holds an array of users. I've done because I plan to use the corporation object to store application session data.
{
"name": "My Corporation",
"prefix": "MYCORP",
"users": [
{
"username": "some#user.com",
"password": "974dae09cd5869958c19e1742117c2f8",
"name": "Freddly the User"
},
{
"username": "other#user.com",
"password": "974dae09cd5869958c19e1742117c2f8",
"name": "Max the Admin"
}
]
}
The problem is when querying after a user (in a log-in scenario) the query, as expected, returns the entire corporation object. Thus I'm exposing all users even though I only want one. As far as security is concerned I guess it isn't a big deal, but I'm more worried about performance. Below is the current query and a very ugly way to delete all users but the one requested.
Ignore the different asserts. Code is very much work-in-progress .. :)
db.collection('kat_corp', function (err, collection) {
try {
assert.equal(null, err);
collection.findOne({
users: {
$elemMatch: {
username: user.username
}
}
}, function (err, result) {
if (err) callback(err, false);
// Delete all other users from the to-be session object
for (var i = 0; i < result.users.length; i++) {
if (result.users[i].username != user.username) {
delete result.users[i];
}
}
// Will be replaced with success callback
console.log(result);
});
} catch (err) {
callback(err, false);
}
});
If you're using MongoDB 2.2 or greater you can just use the "$" positional operator.
The following query worked for me :
db.collection('kat_corp', function (err, collection){
collection.findOne({"users.username":user.username}, {'name':1,'users.$': 1}, console.log)
});
Although I would agree with the other comments that you should probably reconsider your schema...

Categories