Mongoose - Push objects into nested array - javascript

I am trying to push every object inside of an array into an array using Mongoose.
This is an example of what the structure of my playlist collection looks like:
playlist: {
userName: 'user-name',
userId: 'user-id',
playlistArray: [
{
playlistName: 'playlist1',
playlistSongs: [
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
],
},
{
playlistName: 'playlist2',
playlistSongs: [
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
],
},
],
}
I want to push the following array of objects into the playlistSongs array that also has playlistName: 'playlist2' within the same object
[
{ title: '1', duration: 123, uri: 'a' },
{ title: '2', duration: 456, uri: 'b' },
{ title: '3', duration: 789, uri: 'c' },
]
So the result would look like this:
playlist: {
userName: 'user-name',
userId: 'user-id',
playlistArray: [
{
playlistName: 'playlist1',
playlistSongs: [
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
],
},
{
playlistName: 'playlist2',
playlistSongs: [
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
{ title: '', duration: 0, uri: '' },
{ title: '1', duration: 123, uri: 'a' },
{ title: '2', duration: 456, uri: 'b' },
{ title: '3', duration: 789, uri: 'c' },
],
},
],
}
Here is my code trying to update the model:
const newPlaylistSongs = [
{ title: '1', duration: 123, uri: 'a' },
{ title: '2', duration: 456, uri: 'b' },
{ title: '3', duration: 789, uri: 'c' },
];
await playlist
.updateOne(
{},
{
$addToSet: {
'playlistArray.$[pl].playlistSongs': {
$each: {
newPlaylistSongs
}
},
},
},
{
arrayFilters: [
{
'pl.playlistName':'playlist2',
},
],
}
)
.catch(console.error);
But I have gotten this error:
MongoServerError: The argument to $each in $addToSet must be an array but it was of type object

$each is expected with an array value.
$each: []
await playlist
.updateOne(
{},
{
$addToSet: {
'playlistArray.$[pl].playlistSongs': {
$each: newPlaylistSongs
},
},
},
{
arrayFilters: [
{
'pl.playlistName':'playlist2',
},
],
}
)
Sample Mongo Playground

Related

DevExtreme Datagrid Popup with cascading dropdown/lookups?

I would like to find a solution to cascade lookups on a popup form, given that the second lookup needs to set its dataSource at runtime (or calling an API), since the lookup source could be coming from different sources. For example, say that if I selected Arkansas, then it would set a different lookup from a web service call, and if California is selected it would use a call from a database to populate the lookup values.
I have taken the DevExtreme sample below as an example, what events or methods would I need to achieve this?
Code Example:
$(() => {
$('#gridContainer').dxDataGrid({
keyExpr: 'ID',
dataSource: employees,
showBorders: true,
editing: {
allowUpdating: true,
allowAdding: true,
mode: 'popup',
},
onEditorPreparing(e) {
if (e.parentType === 'dataRow' && e.dataField === 'CityID') {
e.editorOptions.disabled = (typeof e.row.data.StateID !== 'number');
}
},
columns: ['FirstName', 'LastName', 'Position',
{
dataField: 'StateID',
caption: 'State',
setCellValue(rowData, value) {
rowData.StateID = value;
rowData.CityID = null;
},
lookup: {
dataSource: states,
valueExpr: 'ID',
displayExpr: 'Name',
},
},
{
dataField: 'CityID',
caption: 'City',
lookup: {
//this is not a static list and will need to be populated when the State changes from various sources...
dataSource(options) {
return {
store: cities,
filter: options.data ? ['StateID', '=', options.data.StateID] : null,
};
},
valueExpr: 'ID',
displayExpr: 'Name',
},
},
],
});
});
Data:
const states = [{
ID: 1,
Name: 'Alabama',
}, {
ID: 2,
Name: 'Alaska',
}, {
ID: 3,
Name: 'Arizona',
}, {
ID: 4,
Name: 'Arkansas',
}, {
ID: 5,
Name: 'California',
}];
const cities = [{
ID: 1,
Name: 'Tuscaloosa',
StateID: 1,
}, {
ID: 2,
Name: 'Hoover',
StateID: 1,
}, {
ID: 3,
Name: 'Dothan',
StateID: 1,
}, {
ID: 4,
Name: 'Decatur',
StateID: 1,
}, {
ID: 5,
Name: 'Anchorage',
StateID: 2,
}, {
ID: 6,
Name: 'Fairbanks',
StateID: 2,
}, {
ID: 7,
Name: 'Juneau',
StateID: 2,
}, {
ID: 8,
Name: 'Avondale',
StateID: 3,
}, {
ID: 9,
Name: 'Buckeye',
StateID: 3,
}];
I managed to resolve the issue using the onEditorPreparing method, basically you have to register the onValueChanged event to manipulate the column cell you need to:
onEditorPreparing: (e): any => {
if (e.parentType === 'dataRow') {
if (e.dataField === 'FieldType') {
e.editorName = 'dxLookup';
$.extend(e.editorOptions, {
showClearButton: true,
dataSource: this.SetDatasource(this.GetArrayDataStore(AdvancedSettingsBuilder.GetFieldTypes)),
valueExpr: 'value',
displayExpr: 'text',
value: e.value || [],
onValueChanged: async (args): Promise<void> => {
e.setValue(args.value);
.........

Transform inherited object to specific key

I have one object and inside the object, there have roles(array of number) and I want to transform only the roles, it should be an array of objects. see below
current object,
displayConfiguration: {
widgetList: {
widgetName: 'widget tiltle',
entityType: 'Asset',
roles: [202]
},
addIcon: {
fileName: '',
fileDownloadUri: ''
},
displayInfoIcon: {
visible: true,
summaryText: 'info icon text'
},
useFilter: true
}
expected object
displayConfiguration: {
widgetList: {
widgetName: 'widget tiltle',
entityType: 'Asset',
roles: [
{
id: 202
}
]
},
addIcon: {
fileName: '',
fileDownloadUri: ''
},
displayInfoIcon: {
visible: true,
summaryText: 'info icon text'
},
useFilter: true
}
const displayConfiguration = {
widgetList: {
widgetName: 'widget tiltle',
entityType: 'Asset',
roles: [202]
},
addIcon: {
fileName: '',
fileDownloadUri: ''
},
displayInfoIcon: {
visible: true,
summaryText: 'info icon text'
},
useFilter: true
}
const answer = {
...displayConfiguration,
widgetList: {
...displayConfiguration.widgetList,
roles: displayConfiguration.widgetList.roles.map(x => ({id: x}))
}
}
console.log(answer)
Should be rather straight forward, you can use map function to transform array
You can you use .map() function, that will walk through each element and convert your number to object that you need.
const displayConfiguration = {
widgetList: {
widgetName: 'widget tiltle',
entityType: 'Asset',
roles: [202]
},
addIcon: {
fileName: '',
fileDownloadUri: ''
},
displayInfoIcon: {
visible: true,
summaryText: 'info icon text'
},
useFilter: true
};
const roles = displayConfiguration.widgetList.roles;
displayConfiguration.widgetList.roles = roles.map(role => {
return {
id: role
}
})
console.log(displayConfiguration);
The map function creates a new array populated with the results of calling a provided function on every element in the calling array.

Rate exceeded error when calling AWS CloudFront update

I have to delete CloudFront distribution using AWS SDK for JavaScript so I'm trying to update it first, but when I sent the request I'm getting Rate exceeded internal server error. I tried many different values inside my config but it always returns this rate error. I'm not sure if it's problem with configuration or maybe I did something else wrong. I have also created function that creates new distribution and it works fine.
My current config object looks like this:
const originId = `S3-${buckets.build.name}`;
const originDomain = `${buckets.build.name}.s3.amazonaws.com`;
const updateParams: CloudFront.UpdateDistributionRequest = {
Id: distribution.id,
IfMatch: distribution.eTag,
DistributionConfig: {
DefaultRootObject: 'index.html',
CallerReference: caller,
Comment: 'Zilo catalog',
DefaultCacheBehavior: {
AllowedMethods: {
Items: ['HEAD', 'GET'],
Quantity: 2,
CachedMethods: {
Items: ['HEAD', 'GET'],
Quantity: 2,
},
},
TargetOriginId: originId,
ViewerProtocolPolicy: 'allow-all',
MinTTL: 3600,
SmoothStreaming: false,
Compress: false,
DefaultTTL: 5000,
FieldLevelEncryptionId: '',
MaxTTL: 10000,
LambdaFunctionAssociations: {
Quantity: 0,
Items: [],
},
ForwardedValues: {
QueryString: true,
Cookies: {
Forward: 'all',
},
Headers: {
Quantity: 0,
Items: [],
},
QueryStringCacheKeys: {
Quantity: 0,
Items: [],
},
},
},
Enabled: false,
Origins: {
Items: [
{
DomainName: originDomain,
Id: originId,
CustomOriginConfig: {
HTTPPort: 80,
HTTPSPort: 443,
OriginProtocolPolicy: 'match-viewer',
OriginSslProtocols: { Items: ['SSLv3'], Quantity: 1 },
OriginReadTimeout: 10000,
OriginKeepaliveTimeout: 10000,
},
OriginPath: '',
CustomHeaders: { Quantity: 0 },
},
],
Quantity: 1,
},
Aliases: {
Quantity: 0,
},
Logging: {
Enabled: false,
IncludeCookies: false,
Bucket: '',
Prefix: '',
},
WebACLId: '',
HttpVersion: 'http2',
Restrictions: {
GeoRestriction: {
RestrictionType: 'none',
Quantity: 0,
},
},
ViewerCertificate: {
MinimumProtocolVersion: 'SSLv3',
},
CustomErrorResponses: {
Items: [],
Quantity: 0,
},
PriceClass: 'PriceClass_100',
CacheBehaviors: { Quantity: 0, Items: [] },
},
};
Any ideas what could gone wrong here?
Ran into this same issue while attempting to disable CloudFront distribution before deleting it. Ended up finding this working solution in Java:
GetDistributionConfigResponse distributionConfigResponse =
cloudFrontClient.getDistributionConfig(GetDistributionConfigRequest.builder().id(distributionId).build());
distributionETag = distributionConfigResponse.eTag();
DistributionConfig originalConfig = distributionConfigResponse.distributionConfig();
UpdateDistributionResponse updateDistributionResponse =
cloudFrontClient.updateDistribution(r -> r.id(distributionId)
.ifMatch(distributionETag)
.distributionConfig(originalConfig.toBuilder()
.enabled(false)
.build()));

What happened to this error? I changed the class name of the table, but I cannot change it and this error occurs?

Help Me please !! What happened to this error? I changed the class name of the table, but I cannot change it and this error occurs?
new gridjs.Grid({
columns: [{ name: 'ID', width: '60px' },
{ name: 'Name', width: '200px' },
{ name: 'Position', width: '300px' },
{ name: 'Email', width: '200px' },
{ name: 'Tel', width: '100px' },
{ name: '', width: '40px', sort: false }],
sort: true,
search: true,
pagination: {
limit: 5,
},
className: {
table: 'table',
thead: 'thead-dark'
},
language: {
'search': {
'placeholder': ' Search...'
},
},
server: {
url: 'http://localhost:55289/ManageUser/GetUserList',
then: data => data.map(user => [user.id,
user.first_name + '\xa0\xa0\xa0' + user.last_name,
user.position, user.email,
user.tel_mobile,
gridjs.html(`<a id="button-delete" href="/ManageUser/Delete/${user.id}"><button class="btn btn-danger"><i class="fa fa-close"></i></button></a>`)])
}
}).render(document.getElementById("user-table"));
As Tammy mentioned, you need to define a custom id for your column:
const grid = new Grid({
columns: [{
id: 'name',
name: 'Name'
}, {
id: 'email',
name: 'Email'
}, {
id: 'phoneNumber',
name: 'Phone Number'
}],
data: [
{ name: 'John', email: 'john#example.com', phoneNumber: '(353) 01 222 3333' },
{ name: 'Mark', email: 'mark#gmail.com', phoneNumber: '(01) 22 888 4444' },
]
});
Demo: https://gridjs.io/docs/examples/import-json
I had the same issue:
Could not find a valid ID for one of the columns.
Make sure a valid "id" is set for all columns
And the fix was what Tammy mentions, I had an empty named column.

Filtering an array of objects with javascript

I have a menu array called "items".
It has submenus.
I need to filter the items with property "visible" equal 1.
I don't know at run time how deep the hierarchy will be.
I need a function returning a new array, with the next conditions:
Every non-matching object with no children, or no matches in children hierarchy, should not exist in output object
Every object with a descendant that contains a matching object, should remain
Only descendants with matching objects should remain
My question is similar to this post Recursively filter array of objects.
But it does not work to me.
I have used the following function, but it´s not working:
const items = [ { icon: "mdi-view-dashboard", title: "Dashboard", to: "/", visible: 1, },
{ title: "Manutenção", icon: "mdi-hammer-screwdriver", to: "", visible: 1,
items: [
{ title: "Usuários", icon: "mdi-account", to: "/usuarios", visible: 1, },
{ title: "Cores", to: "", visible: 1,
items: [
{ title: "Cores da Fila", icon: "mdi-eyedropper-variant", to: "/coresfila", visible: 1, },
{ title: "Cores da Agenda", icon: "mdi-palette", to: "/coresagenda", visible: 1, },
],
},
{ title: "Tabelas Médicas", to: "", visible: 1,
items: [
{ title: "Convênios", icon: "mdi-clipboard-outline", to: "/convenios", visible: 1, },
{ title: "Planos", icon: "mdi-plus-box", to: "/planos", visible: 1, },
{ title: "Especialidades", icon: "mdi-format-font", to: "/especialidadescompletas", visible: 1, },
{ title: "Modelos de Atestados", icon: "mdi-account-details-outline", to: "/modelosAtestados", visible: 1, },
{ title: "Modelos de Prescrições", icon: "mdi-account-edit-outline", to: "/modelosPrescricoes", },
{ title: "Cid-10", icon: "mdi-alphabetical", to: "/cid10", visible: 1, },
{ title: "Procedimentos", icon: "mdi-alarm-plus", to: "/procedimentos", visible: 1, },
{ title: "Materiais", icon: "mdi-table-of-contents", to: "/materiais", visible: 1, },
{ title: "Medicamentos", icon: "mdi-water", to: "/medicamentos", visible: 1, },
{ title: "Taxas", icon: "mdi-cash-100", to: "/taxas", visible: 1, },
],
},
],
},
{ title: "Empresa", icon: "mdi-cash-100", to: "", visible: 1,
items: [ { title: "Perfil da Empresa", icon: "mdi-account-network-outline", to: "/perfilempresa", visible: 1, },
{ title: "Créditos SMS", icon: "mdi-cash-usd-outline", to: "/creditossms", visible: 1, },
],
},
{ title: "Clientes", icon: "mdi-account-alert-outline", to: "/clientes", visible: 1, },
{ title: "Agenda", icon: "far fa-calendar-check", to: "/agenda", visible: 1, },
{ title: "Fila", icon: "mdi-account-multiple-check", to: "/fila", visible: 1, },
{ title: "Atendimento Médico", icon: "fas fa-user-md", to: "/atendimento", visible: 1, },
{ title: "Tela de Chamadas", icon: "mdi-play-network-outline", to: "/telao", visible: 1, },
{ title: "DICOM", icon: "mdi-radioactive-off", to: "/dicom", visible: 1, },
{ title: "Estatísticas", icon: "mdi-chart-box", to: "", visible: 1,
items: [ { title: "Clientes", icon: "mdi-account-arrow-right", to: "", visible: 1,
items: [ { title: "Por convênios", icon: "mdi-poll", to: "/estat_cliente_por_convenios", visible: 1, },
{ title: "Por mês", icon: "mdi-poll", to: "/estat_cliente_por_mes", visible: 1, },
],
},
{ title: "Faturamento", icon: "mdi-cash-usd", to: "", visible: 1,
items: [ { title: "Por convênios", icon: "mdi-poll", to: "/estat_faturamento_por_convenios", visible: 1, },
{ title: "Por mês", icon: "mdi-poll", to: "/estat_faturamento_por_mes", visible: 1, },
], },
], },
{ title: "Autorizações", icon: "mdi-microphone-variant", to: "/listaautorizacoes", visible: 1, },
{ title: "Faturamento", icon: "mdi-cash-usd", to: "", visible: 1,
items: [ { title: "Nova Guia", icon: "mdi-cart-plus", to: "/guiasfaturas", visible: 0, },
{ title: "Lista Guias", icon: "mdi-tray-plus", to: "/listaguias", visible: 1, },
{ title: "Lote de Guias", icon: "mdi-bag-personal", to: "/loteguias", visible: 1, }, ], },
]
function ofilter(arr) {
var matches = [];
if (!Array.isArray(arr)) return matches;
arr.forEach(function(i) {
if (i.visible && i.visible === 1) {
matches.push(i);
} else {
let childResults = this.ofilter(i.items);
if (childResults.length)
matches.push(Object.assign({}, i, {
items: childResults
}));
}
});
return matches;
}
console.log(ofilter(items))
Here's a recursive filter based on a recursive visibility check. This version preserves the nested structure:
const isVisible = item => item.visible
|| item.items?.some(isVisible)
const filterItems = items => {
items.forEach(item => {
if (item.items) item.items = filterItems(item.items)
})
return items.filter(isVisible)
}
console.log(filterItems(
[
{ id: 'a', visible: 1 },
{ id: 'b', visible: 0 },
{
id: 'c',
visible: 0,
items: [
{ id: 'd', visible: 1 },
{ id: 'e', visible: 0 }
]
},
{ id: 'f', visible: 1, items: [{ id: 'g', visible: 0 }] },
{ id: 'h', visible: 0, items: [{ id: 'i', visible: 0 }] },
]
))
Alternatively, here's a version that returns a flat array:
const filterItemsFlat = (items, results = []) => {
items.forEach(item => {
if (item.items) filterItemsFlat(item.items, results)
if (item.visible) results.push(item)
})
results.forEach(r => delete r.items)
return results
}
console.log(filterItemsFlat(
[
{ id: 'a', visible: 1 },
{ id: 'b', visible: 0 },
{
id: 'c',
visible: 0,
items: [
{ id: 'd', visible: 1 },
{ id: 'e', visible: 0 }
]
},
{ id: 'f', visible: 1, items: [{ id: 'g', visible: 0 }] },
{ id: 'h', visible: 0, items: [{ id: 'i', visible: 0 }] },
]
))
Another alternative to question:
const items = [
{ icon: "mdi-view-dashboard", title: "Dashboard", to: "/", visible: 1, },
{ title: "Manutenção", icon: "mdi-hammer-screwdriver", to: "", visible: 0,
items: [
{ title: "Usuários", icon: "mdi-account", to: "/usuarios", visible: 1, },
{ title: "Cores", to: "", visible: 0}
]
}
];
function ofilter(arr) {
let r = [];
arr.forEach((i) => {
if (i.visible == 1) {
r.push(i);
}
if (i.items) {
r.push(ofilter(i.items))
}
})
return r;
}
console.log('result:', ofilter(items))

Categories

Resources