Update embedded array document with Mongoose using req.body - arrays

I have a collection of users and a document can be as follows...
{
_id: ObjectId('this user id'),
firstName: 'first name of this user',
lastName: 'last name of this user',
tvs: [
{
_id: ObjectId('this tv id'),
brand: 'This tv brand',
size: 'this tv size',
},
{
_id: ObjectId('this other tv id'),
brand: 'this other tv brand',
size: 'this other tv size',
}
]
}
I am having trouble trying to update a document embedded in the array of tvs using only req.body. I managed to be able to update the document based on the tv id by doing the following...
await User.updateOne(
{
_id: req.user.id,
'tvs._id': req.params.id,
},
{
$set: { 'tvs.$.brand': req.body.brand },
}
);
but what I want to do is something like this...
await User.updateOne(
{
_id: req.user.id,
'tvs._id': req.params.id,
},
{
$set: { 'tvs.$': req.body },
}
);
where req.body can have many fields and will only update the fields specified and leave the other ones untouched. Problem is that when I do this it changes my element to have only the id and whatever fields I may have in req.body and gets rid of all the other fields.

Related

Cannot read property 'map' of undefined in sequelize nodejs

This is my api:
exports.getService = function(req, res) {
var limit = 10; // number of records per page
var offset = 0;
Service.findAndCountAll({
raw: true,
where: {
shop: req.user.shop
}
}).then((data) => {
var page = req.params.page; // page number
var pages = Math.ceil(data.count / limit);
offset = limit * (page - 1);
Service.findAll({
// raw: true,
limit: limit,
offset: offset,
$sort: {
id: 1
},
where: {
shop: req.user.shop
},
include: [{
model: Categoryservice,
attributes: ['id'],
include: [{
model: Category,
attributes: ['id', 'name'],
}]
}],
}).then(function (services) {
var services=JSON.parse(JSON. stringify(services));
console.log('=====stringify==========>>',services);
var arr = services.categoryservices.map(item => item.category.id)
services.cats = arr;
delete services.categoryservices;
console.log('only for the testing========>',services);
res.status(200).json({
'result': services,
'count': data.count,
'pages': pages
});
});
}).catch(function(error) {
res.status(500).send('Internal Server Error');
});
};
I am using map in last then fuction ,
It contains a error map undefined in the server..
I want want a out like below given json using the map fuction.
Actually i need this out put:
{
"id": 2,
"service": "mobile",
"min": "20",
"per": "10",
"tax": "1",
"cats": [
1,
2
]
}
my JSON. stringify(services) out put is:
=====stringify==========>> [ { id: 2,
username: null,
name: null,
image: null,
service: 'mobile',
shop: '$2a$10$NWpbmgtzQAxRZ1ugvdC7LOlorBU36xoGHm1L.k.KmFqDO/7oSmBLu',
min: '20',
per: '10',
tax: '1',
activity: null,
createdAt: '2018-03-14T07:30:57.000Z',
updatedAt: '2018-03-14T07:30:57.000Z',
categoryservices: [ [Object], [Object] ] },
{ id: 1,
username: 'sam',
name: 'New Service',
image: '/images/uploads/22-Feb-2018/f96334384cd78754454c5e4e05e20fc0-dragon_pattern_red_black_9666_1920x1080.jpg',
service: 'battery',
shop: '$2a$10$NWpbmgtzQAxRZ1ugvdC7LOlorBU36xoGHm1L.k.KmFqDO/7oSmBLu',
min: '5',
per: '1',
tax: '1',
activity: '2018-03-14T06:01:36.000Z',
createdAt: '2018-03-14T06:01:36.000Z',
updatedAt: '2018-03-14T06:01:36.000Z',
categoryservices: [] } ]
I was beginner of using map function,
so,I am confused in map ,
so please give any solution to this problem.
You are stringifying your array that comes back. You can't do that if you plan to use .map on it. Remove that code and try again.
.then(function (services) {
var arr = services.categoryservices.map(item => item.category.id)
services.cats = arr;
delete services.categoryservices;
console.log('only for the testing========>',services);
res.status(200).json({
'result': services,
'count': data.count,
'pages': pages
});
});
I think we are missing something because the output you pasted doesn't have the category.id attribute that you are returning from the item passed in to map. Is that what you are trying to target? That's off topic, but this code may not work for what you are trying to achieve but will run the map though.
Looks like services is an array, based on the console.log. If you want the id's of all categories, you can do
let categoryIds = [];
categoryIds = services.reduce((categoryIds, service) => {
let ids = service.categoryservices.map(category => category.id);
for(let id of ids) {
if(categoryIds.indexOf(id) === -1) {
categoryIds.push(id)
}
}
return categoryIds;
}, categoryIds);
If you want to have category ids as cats in each service, you can do,
var services=JSON.parse(JSON. stringify(services));
services.forEach(service) => {
service.cats = service.categoryservices.map(category => category.id);
delete service.categoryservices;
});
res.status(200).json({
'result': services,
'count': data.count,
'pages': pages
});
Hope this helps!

What schema structure to use for this app?

I want to create an expense tracking app but don't know how to make my schema structure.
The layout:
The schema:
module.exports = {
expenseList: [
{
uid: 'some-uid1',
createdAt: 'some-date1',
expenseItems: [
{
date: 'date11',
desc: 'desc11',
amount: 'amount11'
},
{
date: 'date11',
desc: 'desc11',
amount: 'amount11'
}]
},
{
uid: 'some-uid',
createdAt: 'some-date',
expenseItems: [
{
date: 'date1',
desc: 'desc1',
amount: 'amount1'
},
{
date: 'date1',
desc: 'desc1',
amount: 'amount1'
},
{
date: 'date1',
desc: 'desc1',
amount: 'amount1'
}]
}
]
};
How do I change my schema so I can loop through expenses and display createdAt property as a clickable link that redirects to that expense items?
When do I use Arrays and when do I use Objects in my schema?
Where do I need uid (unique ids)?
I will use firebase for this app
You have an expenseList with a date and expenseItems associated with it. You can have a schema roughly like this. expenseList will be an array of objects. Each expenseList is an object containing uid (to uniquely identify the list), createdAt and array of expenseItems with its own set of properties.
expenseList: [{
uid: 'some-uid',
createdAt: 'some-date',
expenseItems: [
{
date: 'date1',
desc: 'desc1',
amount: 'amount1'
},
{
date: 'date1',
desc: 'desc1',
amount: 'amount1'
}
]
}]
You can iterate over this expenseList to display createdAt in your first screen. On clicking of that, depending on the unique id of that expenseList, fetch the expenseList and display the expenseItems on the second screen.
I have not used firebase before, so you might have to tweak the schema a little.

Mongoose: Update by pushing an object in an array

This is the model I am working with:
name: {
type: String
},
payment: {
id: {
type: String,
required: true
},
cards: [
{
id: {
type: String
},
is_default: {
type: Boolean,
"default": false
}
}
]
}
I want to add a card to the cards array, for example:
card =
id: "some_token"
is_default: true
I am using the update method to push the card to the array, but it won't add the card to the document. Instead, it creates a new document with only those fields:
{
id: "some_token",
is_default: true,
_id: someId
}
Any idea how I can update the actual document I am targeting instead of creating a new document?
Here's my code (using CoffeeScript):
update_where =
payment:
id: "some_id"
update_push =
$push:
'payment.cards':
id: card_token
is_default: false
Customer.update update_where, update_push, {upsert: true}, (err, results) ->
# Do something with the results
Oh… I just noticed my mistake. The problem was in the where statement.
I was doing:
payment:
id: "some_id"
But the right thing to write is the following:
'payment.id': 'some_id'
And it now works!

Update Sequelize Array

I have looked everywhere, and I have not found an easy to understand method of updating a sequelize array, like this with a normal string:
db.User.update({name:req.body.name},{where : {username:req.body.username}}).then(function(user) {
res.json(user);
})
Sequelize doesn't support bulk updates using an array, see https://github.com/sequelize/sequelize/issues/4501
You have to implement a custom function.
Here is a basic example to give you an idea :
var promises = [];
userArray.forEach(function(user){
promises.push(db.User.update({name:user.name},{where : {username:user.username}});
});
Promise.all(promises).then(function(){
// success
}, function(err){
// error
});
Which I myself resolved as follows:
case 1: If you want to update multiple lines at the same value with different conditions
db.User.update({ name: 'name request' }, {
where: {
$or: [{ name: 'test 1', password: 'sasaccsa' }, {
name: "test 2"
}]
}
}).then(function(user) {
//query generate
// UPDATE `User` SET `name`='name request' WHERE ((`name` = 'test 1' AND `password` = 'sasaccsa') OR `name` = 'test 2')
res.json(user);
});
case 2: if you want to update multiple lines with different values for different types of reviews:
var arrayUpdate = [{
name: 'test 1',
id: 1
}, {
name: 'test 2',
id: 2
}, {
name: 'test 3',
id: 3
}];
sequelize.Promise.each(arrayUpdate, function(val, index) {
return db.User.update({
name: val.name
},{
where:{
id: val.id
}
}).then(function(user) {
}, function(err){
});
})
.then(function(updateAll){
//done update all
res.json(updateAll);
}, function(err){
});

UI Bootstrap Typeahead is not displaying the values returned async

I am trying to do an autocomplete search using UI Bootstrap Typeahead to select a data from a database.
My service returns data in my response, but data are not listed in the component.
When I put a breakpoint in the component code , the list is there and when I continue to debug the list is displayed, but if it runs without breakpoints , the list is not displayed.
HTML
<input id="inputInstalation"
ng-model="profile.instalation"
typeahead-editable="false"
typeahead="installation as installation.name for installation in searchInstallation($viewValue)"
typeahead-input-formatter="formatLabel($model)"
ng-required="true">
Controller
$scope.searchInstallation = function(text){
return $http.get('/api/installations/name/' + text).then(function(response){
return response.data;
});
};
$scope.formatLabel = function(model){
return model ? model.name : "";
};
API NodeJS - DB Mongo
exports.findByName = function(req, res){
var connection = getConnection();
var Installation = getInstallationModel(connection);
Installation.find({name: new RegExp(req.params.name, "i")}, function (err, result) {
connection.close();
if(err) throw err;
res.json(result);
});
};
Response
[{ _id: 5525662b74100eb40f13ce00,
name: 'test 2',
description: 'Gdoc 02.02.00-00',
__v: 0,
services:
[ { name: 'Alfresco',
context: '/alfresco',
parameterURL: 'prmGdocServiceUrl',
_id: 5525662b74100eb40f13ce03 },
{ name: 'ri-rest',
context: '/iserver',
parameterURL: 'prmUrlIntegrationServer',
_id: 5525662b74100eb40f13ce02 },
{ name: 'ldap',
parameterURL: 'prmLdapUrl',
parameterUser: 'prmLdapPrincipal',
parameterPassword: 'prmLdapPassword',
_id: 5525662b74100eb40f13ce01 } ],
tables:
[ { _id: 5525662b74100eb40f13ce06, name: 'esegsistema' },
{ _id: 5525662b74100eb40f13ce05, name: 'esegusuario' },
{ _id: 5525662b74100eb40f13ce04, name: 'XPTO' } ],
parameters:
[ { name: 'prmUrlBaseServidorHTTP',
systemCode: '314',
_id: 5525662b74100eb40f13ce0e },
{ name: 'prmTamanhoMaximoArquivo',
systemCode: '314',
_id: 5525662b74100eb40f13ce0d },
{ name: 'prmGdocServiceUrl',
systemCode: '314',
_id: 5525662b74100eb40f13ce0c },
{ name: 'prmLdapUrl',
systemCode: '314',
_id: 5525662b74100eb40f13ce0b },
{ name: 'prmLdapPrincipal',
systemCode: '314',
_id: 5525662b74100eb40f13ce0a },
{ name: 'prmLdapPassword',
systemCode: '314',
_id: 5525662b74100eb40f13ce09 },
{ name: 'prmDomainSufix',
systemCode: '314',
_id: 5525662b74100eb40f13ce08 },
{ name: 'xxxxx',
systemCode: '314',
_id: 5525662b74100eb40f13ce07 } ] }]
I found the problem, I'm using the https://github.com/McNull/angular-block-ui and it conflicts with the component.
Solution : I created a requestFilter from angular blockui to don't block requests sent the component to API .

Resources