Exclude Empty association array using Sequelize - mysql

I have a menus table with a one-to-many self association so basically structure is like
---Menu
|
'--submenu
|
'--submenu
---secondMenu
|
'--submenu
|
'--submenu
|
'--submenu
---thirdMenu
Consider the third menu that does not have any submenu. In that case I want the submenu field to be null or this field should not be attached. I get results like
"menu": [
{
"name": "Settings",
"id": 37,
"slug": "Settings-ecom",
"url": "/Settings",
"submenu": [
{
"name": "Settings-child1",
"id": 38,
"slug": "Settings-ecom-child1",
"url": "/Settings-child1",
"submenu": [
{
"name": "Settings-child1-child1",
"id": 40,
"slug": "Settings-ecom-child1-child1",
"url": "/Settings-child1-child1",
"submenu": []
}
]
}
]
},
{
"name": "Dashboard",
"id": 30,
"slug": "dashboard-ecommerce",
"url": "/dashboard",
"submenu": []
}
]
consider the submenu=[] part in the result, what I need is that when there is no submenu it should not return submenu = [] . either it should exclude submenu or it should be something like submenu = null
below is my query to get menus
const menu = await Menu.findAll({
where: {parent_id: null},
attributes: Constants.attributes,
include: [
{
model: Menu,
as: 'submenu',
attributes: Constants.attributes,
include: [
{
model: Menu,
as: 'submenu',
attributes: Constants.attributes,
},
],
},
],
});
and finally the association is like
menu.hasMany(models.menu, {
as: 'submenu',
foreignKey: 'parent_id',
useJunctionTable: false,
});
Thanks for looking over my question :)

Ok so I found a solution, that is to recursively delete empty submenu object from the final result. Hope it might help someone
cleanMenusObject = async (menuToUpdate) => {
for (let menu of menuToUpdate) {
if (menu.dataValues.submenu) {
if (!menu.dataValues.submenu.length) {
delete menu.dataValues.submenu;
} else {
await cleanMenusObject(menu.dataValues.submenu);
}
}
}
};

Related

MongoDB: Select from one collection based on another collection

I'm new to MongoDB and I'm trying to find a category that meets the required params. I have two collections, categories (list of categories) and ref_categories (manages nested category relationships)
collection categories:
[
{
"id": "A1001",
"key": "3dmodels",
},
{
"id": "A1002",
"key": "animals",
},
{
"id": "A1003",
"key": "birds",
},
{
"id": "A1004",
"key": "reptiles",
},
{
"id": "A1005",
"key": "birds",
}
]
collection categories_ref:
[
{
"category_id": "A1001", // 3dmodels parented to
"p_category_id": "root", // root
},
{
"category_id": "A1002", // animals parented to
"p_category_id": "A1001", // 3dmodels
},
{
"category_id": "A1003", // birds parented to
"p_category_id": "A1002", // animals
},
{
"category_id": "A1004", // reptiles parented to
"p_category_id": "A1002", // animals
},
{
"category_id": "A1005", // birds parented to
"p_category_id": "A1004", // reptiles
}
]
You'll noticed in my Categories collection there are two entries for 'birds' however they each have a different parent category.
I'm trying to create a query that allows me to find the category by key and parent category key.
Pseudo example.... I want to find 'birds' but the entry who has a parent called 'animals'. Otherwise return null.
the expected output would be
// find category_key: "birds" parent_category_key: "animals"
{
"id": "A1003",
"key": "birds",
}
You can use a $lookup with a pipeline where you match two conditions:
Join based on id. Categories id is the same as reference category_id.
Also check p_category_id is the desired code.
And after that you can $match to not get elements where the join result is empty (i.e, keep elements where exists a value).
db.categories.aggregate([
{
"$match": {"key": "birds"}
},
{
"$lookup": {
"from": "categories_ref",
"let": {"id": "$id"},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{
"$eq": ["$category_id","$$id"]
},
{
"$eq": ["$p_category_id","A1002"]
}
]
}
}
}
],
"as": "cat_ref"
}
},
{
"$match": {"cat_ref": {"$ne": []}}
},
{
"$project": {"cat_ref": 0}
}
])
Example here

How to refer sibling element in JSON Javascript?

I have a json object for chart like below:
{
"results": [
{
"dataSets": {
"One": {
"label": "testLabel",
"labels": "test",
"data": [
"10",
"58"
]
}
},
"chart": [
{
"key": "test",
"label": "chart-1",
"chartType": "bar",
"order": "1",
"dataSets": [
{
"style": "line",
"key": "One"
},
]
}
]
}
]
}
I want to get dataSets values like label, labels, data of “one” in chart’s dataSets by providing “one” as key.
Is it possible to do in javascript or vue?
Yes, it is possible. But you will need to make a series of Array.map() to achieve this.
const results = [{
dataSets: {
One: {
label: "testLabel",
labels: "test",
data: ["10", "58"]
}
},
chart: [{
key: "test",
label: "chart-1",
chartType: "bar",
order: "1",
dataSets: [{
style: "line",
key: "One"
}]
}]
}];
const modifiedResult = results.map(result => {
const outerDataSets = result.dataSets;
result.chart = result.chart.map(chart =>
chart.dataSets.map(innerDataSet => ({
...innerDataSet,
...outerDataSets[innerDataSet.key]
}))
);
return result;
});
console.log(modifiedResult);
Also if you are working with Vue, I think its best to put the modification of result on the computed so it will always try to add those dataSets additional data to the chart's dataSets.
Here a sample demo for implementation in Vue.

sub document under main document how to get a listing with pagination using couchbase(N1QL) query

any one can help me how to get the sub document List with pagination
i just give a sample example :
{
"accessories": [`
{
"data": {
"name": "TEST",
"updated_at": "2020-03-27T16:16:20.818Z"
},
"id": "56e83ea1-042e-47e0-85f8-186189c37426"
}
],
"calibration_reports": [`
{
"data": {
"deleted_at": "",
"frm27_equipment": [
"test_cat1"
],
"frm27_link": [
"yes"
],
"frm27_submit": null,
"updated_at": "2020-03-30T10:24:52.703Z"
},
"id": "e4c8b1b4-7f37-46db-a49d-bca74482b968"
},
{
"data": {
"deleted_at": "",
"frm27_equipment": [
"test_cat1"
],
"frm27_link": [
"no"
],
"frm27_submit": null,
"updated_at": "2020-03-30T10:34:37.615Z"
},
"id": "445854d6-66bf-4e33-b620-05a5053119a8"
}
],
}
]
}
Here i want to get a calibration_reports list with pagination is it possible ? using couchbase (N1ql Query)
please if any one know, what is the process how to get the list of result with pagination using couchbase(N1QL) query. please help me.
One possible way to go about this is to use UNNEST.
For instance:
SELECT calreports.id
FROM utpal u
UNNEST u.calibration_reports calreports
This would return something like:
[
{ "id": "aaa" },
{ "id": "bbb" },
{ "id": "ccc" },
... etc ...
]
And then you can use normal LIMIT/OFFSET for pagination, like so:
SELECT calreports.id
FROM utpal u
UNNEST u.calibration_reports calreports
LIMIT 50
OFFSET 150;

Sequelizejs: How to eager load a 'structured' assosiation?

I have a database scheme like this:
Scheme image
The only relation I made is this:
db.routines.hasMany(db.elements, {constraints: false});
I'm trying to find a routine, with all elements populated/eager-loaded, but I don't know how to achieve this, I'm trying this:
db.routines.findAll({
include: [{ all: true }]
}).then(routines => {
res.send(routines)
})
or
db.routines.findAll({
include: [{
model: db.elements
}]
}).then(routines => {
res.send(routines)
})
Both result in the following:
[
{
"id": "f45273da-eb13-45a2-852c-81b8eee14eb8",
"element_1": "8d609633-1554-41cd-a47e-244508ebe77c",
"element_2": "8d609633-1554-41cd-a47e-244508ebe77c",
"element_3": "8d609633-1554-41cd-a47e-244508ebe77c",
"element_4": "8d609633-1554-41cd-a47e-244508ebe77c",
"element_5": "8d609633-1554-41cd-a47e-244508ebe77c",
"diff1": null,
"diff2": null,
"created_at": "2017-12-12T21:04:15.000Z",
"updated_at": "2017-12-12T21:04:15.000Z",
"deleted_at": null,
"elements": []
}
]
But what I'm looking for is something like this:
[
{
"id": "f45273da-eb13-45a2-852c-81b8eee14eb8",
"element_1": {
"id": "8d609633-1554-41cd-a47e-244508ebe77c",
"name_en": "Backflip",
"name_nl": "Salto",
.....
},
"element_2": {
"id": "8d609633-1554-41cd-a47e-244508ebe77c",
"name_en": "Backflip",
"name_nl": "Salto",
.....
},
"element_3": {
"id": "8d609633-1554-41cd-a47e-244508ebe77c",
"name_en": "Backflip",
"name_nl": "Salto",
.....
},
.....
}
]
How do I populate this? The only examples I find are retrieving an object of elements, which is not what I want, since they have to have a specific index.

Using JSON API Serializer to create more complicated JSON

The examples here don't go nearly far enough in explaining how to produce a more complicated structure...
If I want to end up with something like:
{
"data": {
"type": "mobile_screens",
"id": "1",
"attributes": {
"title": "Watch"
},
"relationships": {
"mobile_screen_components": {
"data": [
{
"id": "1_1",
"type": "mobile_screen_components"
},
{
"id": "1_2",
"type": "mobile_screen_components"
},
...
]
}
}
},
"included": [
{
"id": "1_1",
"type": "mobile_screen_components",
"attributes": {
"title": "Featured Playlist",
"display_type": "shelf"
},
"relationships": {
"playlist": {
"data": {
"id": "938973798001",
"type": "playlists"
}
}
}
},
{
"id": "938973798001",
"type": "playlists",
"relationships": {
"videos": {
"data": [
{
"id": "5536725488001",
"type": "videos"
},
{
"id": "5535943875001",
"type": "videos"
}
]
}
}
},
{
"id": "5536725488001",
"type": "videos",
"attributes": {
"duration": 78321,
"live_stream": false,
"thumbnail": {
"width": 1280,
"url":
"http://xxx.jpg?pubId=694940094001",
"height": 720
},
"last_published_date": "2017-08-09T18:26:04.899Z",
"streams": [
{
"url":
"http://xxx.m3u8",
"mime_type": "MP4"
}
],
"last_modified_date": "2017-08-09T18:26:27.621Z",
"description": "xxx",
"fn__media_tags": [
"weather",
"personality"
],
"created_date": "2017-08-09T18:23:16.830Z",
"title": "NOAA predicts most active hurricane season since 2010",
"fn__tve_authentication_required": false
}
},
...,
]
}
what is the most simple data structure and serializer I can set up?
I get stumped after something like:
const mobile_screen_components = responses.map((currentValue, index) => {
id[`id_${index}`];
});
const dataSet = {
id: 1,
title: 'Watch',
mobile_screen_components,
};
const ScreenSerializer = new JSONAPISerializer('mobile_screens', {
attributes: ['title', 'mobile_screen_components'],
mobile_screen_components: {
ref: 'id',
}
});
Which only gives me:
{
"data": {
"type": "mobile_screens",
"id": "1",
"attributes": { "title": "Watch" },
"relationships": {
"mobile-screen-components": {
"data": [
{ "type": "mobile_screen_components", "id": "1_0" },
{ "type": "mobile_screen_components", "id": "1_1" },
{ "type": "mobile_screen_components", "id": "1_2" },
{ "type": "mobile_screen_components", "id": "1_3" },
{ "type": "mobile_screen_components", "id": "1_4" },
{ "type": "mobile_screen_components", "id": "1_5" }
]
}
}
}
}
I have no idea how to get the "included" sibling to "data." etc.
So, the question is:
what is the most simple data structure and serializer I can set up?
Below is the simplest object that can be converted to JSON similar to JSON in the question using jsonapi-serializer:
let dataSet = {
id: '1',
title: 'Watch',
mobile_screen_components: [
{
id: '1_1',
title: 'Featured Playlists',
display_type: 'shelf',
playlists: {
id: 938973798001,
videos: [
{
id: 5536725488001,
duration: 78321,
live_stream: false
},
{
id: 5535943875001,
duration: 52621,
live_stream: true
}
]
}
}
]
};
To serialize this object to JSON API, I used the following code:
let json = new JSONAPISerializer('mobile_screen', {
attributes: ['id', 'title', 'mobile_screen_components'],
mobile_screen_components: {
ref: 'id',
attributes: ['id', 'title', 'display_type', 'playlists'],
playlists: {
ref: 'id',
attributes: ['id', 'videos'],
videos: {
ref: 'id',
attributes: ['id', 'duration', 'live_stream']
}
}
}
}).serialize(dataSet);
console.log(JSON.stringify(json, null, 2));
The first parameter of JSONAPISerializer constructor is the resource type.
The second parameter is the serialization options.
Each level of the options equals to the level of the nested object in serialized object.
ref - if present, it's considered as a relationships.
attributes - an array of attributes to show.
Introduction
First of all we have to understand the JSON API document data structure
[0.1] Refering to the top level (object root keys) :
A document MUST contain at least one of the following top-level
members:
data: the document’s “primary data”
errors: an array of error objects
meta: a meta object that contains non-standard meta-information.
A document MAY contain any of these top-level members:
jsonapi: an object describing the server’s implementation
links: a links object related to the primary data.
included: an array of resource objects that are related to the primary data and/or each other (“included resources”).
[0.2]
The document’s “primary data” is a representation of the resource or
collection of resources targeted by a request.
Primary data MUST be either:
a single resource identifier object, or
null, for requests that target single resources
an array of resource identifier
objects, or an empty array ([]), for reqs. that target
collections
Example
The following primary data is a single resource object:
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
// ... this article's attributes
},
"relationships": {
// ... this article's relationships
}
}
}
In the (jsonapi-serializer) documentation : Available serialization option (opts argument)
So in order to add the included (top-level member) I performed the following test :
var JsonApiSerializer = require('jsonapi-serializer').Serializer;
const DATASET = {
id:23,title:'Lifestyle',slug:'lifestyle',
subcategories: [
{description:'Practices for becoming 31337.',id:1337,title:'Elite'},
{description:'Practices for health.',id:69,title:'Vitality'}
]
}
const TEMPLATE = {
topLevelLinks:{self:'http://example.com'},
dataLinks:{self:function(collection){return 'http://example.com/'+collection.id}},
attributes:['title','slug','subcategories'],
subcategories:{ref:'id',attributes:['id','title','description']}
}
let SERIALIZER = new JsonApiSerializer('pratices', DATASET, TEMPLATE)
console.log(SERIALIZER)
With the following output :
{ links: { self: 'http://example.com' },
included:
[ { type: 'subcategories', id: '1337', attributes: [Object] },
{ type: 'subcategories', id: '69', attributes: [Object] } ],
data:
{ type: 'pratices',
id: '23',
links: { self: 'http://example.com/23' },
attributes: { title: 'Lifestyle', slug: 'lifestyle' },
relationships: { subcategories: [Object] } } }
As you may observe, the included is correctly populated.
NOTE : If you need more help with your dataSet, edit your question with the original data.