How to deserialize included model properties? - javascript

I'm getting a string path (floated, dotted) for included table instead object with properties.
Where do I need to set the deserialization?
I tried receive value through object["object.id"] but it's not my choice
Model.findAll({
include: [{
model: Model2
}],
raw: true
}).then(elems => {
res.send(
elems.map(elem => {
return {
id: elem.id,
name: elem["model2table.model2name"]
}
})
)
Expected: elem.model2table.model2name
Actual: elem["model2table.model2name"]

Remove raw:true from findAll params like this:
Model.findAll({
include: [{
model: Model2
}]
}).then(elems => {
res.send(
elems.map(elem => {
return {
id: elem.id,
name: elem["model2table.model2name"]
}
})
)
Answer was founded here

Related

Map the nested data from other table using promise and async-await

I need the expert advice for this code. I need to know Is there any better way to solve this.
I am using the mongoose for db. I have a dataset like this:
Below is matchTable:
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
}
],
status: true
}
And I have a Car table in which car name is there on behalf of id
like this
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febce'), name: 'ford' },
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febcg'), name: 'mitsubishi' },
So I want to make join the data from car table, so that response get name on behalf of aid.
Desired result will be like
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
name: 'mitsubishi'
}
],
status: true
}
For that I have to merge the car table on matchTable. I have done this but I want to give some suggestion that is there any better way to do or is it fine. I need expert advice.
const getData = await matchTable.find(
{ status: true }
).lean().exec();
let dataHolder = [];
await Promise.all (
getData.map(async x => {
await Promise.all(
x.car.map(async y => {
let data = await Car.findOne(
{ _id: ObjectId(y.aid) },
{ name: 1 }
).lean().exec();
y.name = '';
if (data) {
y.name = data.name;
}
})
)
// If I return { ...x }, then on response it will return {}, {} on car column
dataHolder.push(x) //So I have chosen this approach
})
);
Please guide me if any better and efficient solution is there. Thanks in advance
You can make use of aggregation here.
const pipeline = [
{
$match : { status : true }
},
{
$unwind: '$matchtable',
},
{
$lookup: {
from: "cars",
localField: "car.aid",
foreignField: "_id",
as: "matchcars"
}
},
{
$addFields: {
"car.carName": { $arrayElemAt: ["$matchcars.name", 0] }
}
},
{
$group: {
_id: "$_id",
cars: { $push: "$matchcars" }
}
}
]
const result = await matchTable.aggregate(pipeline).exec();
Please make sure, aid field inside car array (in matchTable collection) is an ObjectId because its being matched to _id (which is an ObjectId) inside cars collection.

Sequelize get own attributes only, ignore included instances

What I'm looking for is an instance method in Model that will return only the attributes of that model & exclude instances of any included model.
eg: Imagine I have 2 models, with a hasMany ( or any ) association:
Post {
id,
content,
user_id
}
User: {
id,
name,
}
and I have:
const userWithPosts = await User.findOne({
where: { id: 33 },
include: [{
model: Post,
as: 'posts'
}]
});
console.log(userWithPosts)
/*
{
id: 33,
name: 'John Doe',
posts: [
Post {
id: 1,
content: '..',
user_id: 33
},
Post {
id: 2,
content: '...',
user_id: 33
}
]
}
*/
I'm looking for a method, say getOwnAttributes or something like that which does:
userWithPosts.getOwnAttributes()
/*
{
id: 33,
name: 'John Doe',
}
*/
I've looked into couple of things:
userWithPosts.get({ raw: true })
userWithPosts.get({ plain: true })
userWithPosts.toJSON()
All of the above returns included instances as well.
Any existing method or workaround that can do this?
EDIT: I'm not talking about doing it at query time, but getting the value from already queried instance. Currently my work-around for this is:
const payload = _.pick(userWithPosts.toJSON(), [
...Object.keys(User.rawAttributes),
]);
You can refer to the code below to exclude attributes of Post table.
const userWithPosts = await User.findOne({
where: { id: 33 },
include: [{
model: Post,
as: 'posts',
attributes: []
}]
});
I hope it helps!

How to return an array of objects in GraphQL, possibly using the same endpoint as the one that returns a single object?

I am making a GraphQL API where I would be able to retrieve a car object by its id or retrieve all the cars when no parameter is provided.
Using the code below, I am successfully able to retrieve a single car object by supplying id as a parameter.
However, in the case where I would expect an array of objects i.e. when I supply no parameter at all, I get no result on GraphiQL.
schema.js
let cars = [
{ name: "Honda", id: "1" },
{ name: "Toyota", id: "2" },
{ name: "BMW", id: "3" }
];
const CarType = new GraphQLObjectType({
name: "Car",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString }
})
});
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
cars: {
type: CarType,
args: {
id: { type: GraphQLString }
},
resolve(parent, args) {
if (args.id) {
console.log(cars.find(car => car.id == args.id));
return cars.find(car => car.id == args.id);
}
console.log(cars);
//***Problem Here***
return cars;
}
}
}
});
Test queries and their respective results:
Query 1
{
cars(id:"1"){
name
}
}
Query 1 Response (Success)
{
"data": {
"cars": {
"name": "Honda"
}
}
}
Query 2
{
cars{
name
}
}
Query 2 Response (Fail)
{
"data": {
"cars": {
"name": null
}
}
}
Any help would be much appreciated.
A Car and a List of Cars are effectively two separate types. A field cannot resolve to a single Car object one time, and an array of Car object another.
Your query is returning null for the name because you told it the cars field would resolve to a single object, but it resolved to an array instead. As a result, it's looking for a property called name on the array object and since one doesn't exist, it's returning null.
You can handle this in a couple of different ways. To keep things to one query, you can use filter instead of find and change the type of your query to a List.
cars: {
type: new GraphQLList(CarType), // note the change here
args: {
id: {
type: GraphQLString
},
},
resolve: (parent, args) => {
if (args.id) {
return cars.filter(car => car.id === args.id);
}
return cars;
}
}
Alternatively, you could split this into two separate queries:
cars: {
type: new GraphQLList(CarType),
resolve: (parent, args) => cars,
},
car: {
type: CarType,
args: {
id: {
// example of using GraphQLNonNull to make the id required
type: new GraphQLNonNull(GraphQLString)
},
},
resolve: (parent, args) => cars.find(car => car.id === args.id),
}
Check the docs for more examples and options.

Loop through JS Object and function on each item

I must be over thinking the solution for this problem but can't seem to get this right.
I have an array object like so:
[
{ ItemID: 1, Path: '/Admin', Name: 'Admin' },
{ ItemID: 2, Path: '/Product', Name: 'Product' },
{ ItemID: 1, Path: '/Reports', Name: 'Reports' }
]
I want to map over each item and for each one I need to run a function that will return whether they have access. i.e. a boolean (yes/no).
So far I have something like this:
const newData = data.map((curr, val , arr) => {
if (checkAccess(username, curr.Name )) { //checkAccess returns true or false
return { ...current };
}
});
I only want to return the ones they have access to.
so assuming that a user is unable to access Admin the final object should be:
[
{ ItemID: 2, Path: '/Product', Name: 'Product' },
{ ItemID: 1, Path: '/Reports', Name: 'Reports' }
]
EDIT:
The issue is also that the function isn't returning a true / false
function checkInGroup(username, name) {
let inGroup = "";
ad.isUserMemberOf(username, name, function(err, isMember) {
if (err) {
return res.json("Error ", err);
}
inGroup = isMember; //this part returns true
});
return inGroup; //this seems to return empty string
}
try using filter, as it creates a new array with all elements that pass the condition:
const res = data.filter(obj => obj.Path !== '/Admin');
console.log(res);

Remove parent object of a JSON if it has certain property

I'm getting a JSON structure from an API, that I want to change in my front end. The frontend adds a property to the JSON structure, "isHidden". When I send the modified JSON back, I don't want the object that has "isHidden" to be sent back to the API, but I will still save that internally in my own mongodb.
However, doing this was aperently a bit harder then I thought. I made this function wich works but I think is very ugly:
function removeHiddenObject(data,parent){
for(var property in data){
if(data.hasOwnProperty(property)){
if(property == "isHidden" && data[property] === true){
parent.splice(parent.indexOf(data), 1);
}
else {
if(typeof data[property] === "object") {
removeHiddenObject(data[property], data);
}
}
}
}
return data;
}
It's a recursive method, but I find it way to complex and weird. Is there a way of simplifying my task?
Here is a jsfiddle for you if you'd like to help out: https://jsfiddle.net/vn4vbne8/
use this code to remove it from json string :
myJson=s.replace(/,*\s*"[^"]"\s*\:\s*{(.*?)"isHidden"\:([^}]*)}/gm,"");
Be careful in Regex every character is important so use exactly above code.
It removes every property that have an object that one of its properties is isHidden.
Javascript actually supports non-enumerable public properties. I'm assuming that when you send data back to the server you first stringify it with JSON.stringify which will only stringify public enumerable properties of the object.
You can define a non-enumerable property like this (more on this here):
Object.defineProperty(obj, 'isHidden', {
enumerable: false,
writable: true
});
Where obj is the javascript object you want to add the property to and isHidden is the name of the property you are adding. When done this way, the new property is accessible as obj.isHidden but nevertheless will not show up in JSON.stringify output nor in for loops.
Here is a solution using object-scan. Takes a bit of time to wrap your head around it, but it helps with some heavy lifting around general data processing.
// const objectScan = require('object-scan');
const data = {"user":{"name":"Bob"},"buildingBlockTree":[{"uid":"a875ed6cf4052448f9e0cc9ff092a76d4","_id":"56a7353f682e1cc615f4a6ae","columns":[{"uid":"a0061fdd2259146bb84e5362eeb775186","_id":"56a7353f682e1cc615f4a6b1","buildingBlocks":[{"user":{"name":"lajdi"},"buildingBlockTree":[{"uid":"a875ed6cf4052448f9e0cc9ff092a76d4","_id":"56a7353f682e1cc615f4a6ae","columns":[{"uid":"a0061fdd2259146bb84e5362eeb775186","_id":"56a7353f682e1cc615f4a6b1","buildingBlocks":[]},{"uid":"abbcf3328854840deb96bb6b101df2b39","_id":"56a7353f682e1cc615f4a6af","buildingBlocks":[{"uid":"a931cf745d4b847ba9cdc7f4b830413be","_id":"56a7353f682e1cc615f4a6b0","source":{"limit":1,"itemsListId":1,"offset":0}}]}],"template":{"name":"Xs12Sm12Md6Lg12DotXs12Sm12Md6Lg12"}}],"_id":"56a7353f682e1cc615f4a6ad","source":{"limit":1,"itemsListId":1,"offset":0},"template":{"numberOfColumns":1},"uid":"a5f6a2fd1c80f49c0b97e0c7994400588"}]},{"uid":"abbcf3328854840deb96bb6b101df2b39","_id":"56a7353f682e1cc615f4a6af","buildingBlocks":[{"_id":"56a7353f682e1cc615f4a6b0","source":{"limit":1,"itemsListId":1,"offset":0},"isHidden":true}]}]}],"_id":"56a7353f682e1cc615f4a6ad","source":{"limit":1,"itemsListId":1,"offset":0},"uid":"a5f6a2fd1c80f49c0b97e0c7994400588","metadata":{"title":"sss"},"title":"sss","url":"sss"};
const removeHiddenObjects = (input) => objectScan(['**[*].isHidden'], {
rtn: 'count',
filterFn: ({ value, gparent, gproperty }) => {
if (value === true) {
gparent.splice(gproperty, 1);
return true;
}
return false;
}
})(input);
console.log(removeHiddenObjects(data)); // counts removals
// => 1
console.log(data);
/* => {
user: { name: 'Bob' },
buildingBlockTree: [ {
uid: 'a875ed6cf4052448f9e0cc9ff092a76d4',
_id: '56a7353f682e1cc615f4a6ae',
columns: [ {
uid: 'a0061fdd2259146bb84e5362eeb775186',
_id: '56a7353f682e1cc615f4a6b1',
buildingBlocks: [ {
user: { name: 'lajdi' },
buildingBlockTree: [ {
uid: 'a875ed6cf4052448f9e0cc9ff092a76d4', _id: '56a7353f682e1cc615f4a6ae', columns: [
{ uid: 'a0061fdd2259146bb84e5362eeb775186', _id: '56a7353f682e1cc615f4a6b1', buildingBlocks: [] },
{ uid: 'abbcf3328854840deb96bb6b101df2b39', _id: '56a7353f682e1cc615f4a6af', buildingBlocks: [
{ uid: 'a931cf745d4b847ba9cdc7f4b830413be', _id: '56a7353f682e1cc615f4a6b0', source: {
limit: 1,
itemsListId: 1,
offset: 0
} }
] }
],
template: { name: 'Xs12Sm12Md6Lg12DotXs12Sm12Md6Lg12' }
} ],
_id: '56a7353f682e1cc615f4a6ad',
source: { limit: 1, itemsListId: 1, offset: 0 },
template: { numberOfColumns: 1 },
uid: 'a5f6a2fd1c80f49c0b97e0c7994400588'
} ]
}, { uid: 'abbcf3328854840deb96bb6b101df2b39', _id: '56a7353f682e1cc615f4a6af', buildingBlocks: [] } ]
} ],
_id: '56a7353f682e1cc615f4a6ad',
source: { limit: 1, itemsListId: 1, offset: 0 },
uid: 'a5f6a2fd1c80f49c0b97e0c7994400588',
metadata: { title: 'sss' },
title: 'sss',
url: 'sss'
}
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#16.0.0"></script>
Disclaimer: I'm the author of object-scan

Categories

Resources