Search results on nested fields (within relations) in Sails.js (waterline) - javascript

I'm using Sails.js (waterline orm), to make an API
What I need and couldn't accomplish is filter results from a table (model), searching in all fields including nested ones:
I.e.:
GET /users/?filter=admin
>>> [{ id: 1, email: 'homer#example.com', role: 'admin' },
{ id: 3, email: 'lisa#example.com', role: 'admin' }]
GET /users/?filter=homer
>>> [{ id: 1, email: 'homer#example.com', role: 'admin' }]
models/Users.js
{
attributes: {
email: {
type: 'string'
},
role: {
model: 'Roles'
}
}
}
models/Roles.js
{
attributes: {
role: {
type: 'string'
}
}
}

You seem to be using the included REST api for waterline. I have used sails in a recent project, and I can say that the REST api is missing features compared to the JavaScript library.
I'd recommend you create your own api endpoint using a sails controller and write your request in JavaScript directly (using where and populate).

Related

Gatsby createResolvers for data types within other data types

I've got this data set:
const avengers = [
{
firstName: 'Tony',
lastName: 'Stark',
name: 'Iron Man',
bestFriends: {
name: 'Captain America',
},
},
{
firstName: 'Bruce',
lastName: 'Banner',
name: 'Hulk',
bestFriends: {
name: 'Black Widow',
},
},
{
firstName: 'Thor',
lastName: 'Odinson',
name: 'Thor',
bestFriends: {
name: 'Rocket',
},
},
]
and what I'm trying to accomplish in Gatsby is to extend the bestFriends node in my Gatsby Nodes and allow the bestFriend's data to be fetched via a single query. My result query would look like this:
query myQuery {
Avenger (name: {eq: "Iron Man}) {
name
firstName
lastName
bestFriends {
name
friendData {
firstName
lastName
name
bestFriends
}
}
}
}
However I'm struggling to figure out how to set up my createResolvers so that I can set a custom resolver function for the friendData node. It almost seems as if the Gatsby createResolvers API isn't able to resolve nested data sets. I assumed that this should work but when I do query the data via GraphiQL the node bestFriends returns "null".
createResolvers({
Avenger: {
bestFriends: {
type: "Avenger",
resolve: (source, args, context) => {
return context.nodeModel.runQuery({
query: {
filter: {
name: {eq: source.bestFriends.name}
}
}
})
}
}
}
})
};
Any idea how I can accomplish what I'm getting at? I imagine that this is how Facebook would set up data structures for posts and comments, where the commentor's name, profile url, profile picture, and the comment itself is visible when you look at a post.

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!

What does this 'child' in my javascript array mean?

I keep getting these 'child' things in my Javascript collection after certain operations. The 'child' keyword is showing up in my terminal after logging the Javascript collection.
Whats strange is that I can't actually find good documentation anywhere online on what this means. Seems like it should be a basic concept.
When I do google it I just get a ton of results for 'child' in context of HTML and the DOM.
What does it mean in javascript? And how could I fix this collection to have these nested collections without the 'child' thing.
Gosh I wish I could speak about it with more sophistication :p
More Context on How This 'Bad' Collection is Generated
So I'm trying to populate JSON data from my Mongodb database and return it to the frontend. Essentially I have nested collections like so:
Institution
|
------------> memberOrganizations
|
---------------------> associatedVIPs
Where I'm originally grabbing Institutions I can populate collections one level down using built in populate functionality.
Doing like so:
Institution.find()
.populate('memberOrganizations')
.then(function (institutions) {
console.log("All institutions, memberOrganizations populated no problem.");
return res.json(institutions);
});
The problem is coming in when I try to go populate collections inside those member organizations, and replace existing memberOrganizations data with that.
Institution.find()
.populate('memberOrganizations')
.then(function (institutions) {
var populateOrganizationOrderManagers = _.map(institutions, function (institution) {
var masterInstitution = _.cloneDeep(institution);
return new Promise(function (resolve, reject) {
var ids = _.map(institution.memberOrganizations, 'id');
Organization.find(ids).populate('associatedVIPs').then(function (orgs) {
masterInstitution.memberOrganizations = orgs;
resolve(masterInstitution);
});
});
});
return Promise.all(populateOrganizationOrderManagers)
.then(function (institutionsWithOrderManagers) {
return res.json(institutionsWithOrderManagers);
});
})
Printouts of the JSON data using console.log to print to my terminal
(Simplified all data by a bit to make it easier to make a point)
What it looks like:
[ child {
memberOrganizations:
[ { associatedVIPs:
[ { firstName: 'Gregory',
lastName: 'Parker',
email: 'info#parker2018.com',
id: '5ab94183164475010026184b' } ],
institution: '5ab940b71644750100261845',
name: 'Greg Parker',
type: 'Student',
id: '5ab941401644750100261847' },
{ associatedVIPs:
[ { firstName: 'Irma',
lastName: 'Francisco',
email: 'irmaf#houstontransporter.com',
id: '5ae348da1ef63b245a74fe2d' } ],
institution: '5ab940b71644750100261845',
name: 'Transporter Inc',
type: 'Other',
id: '5ae3488d1ef63b2c8f74fe29' } ],
name: 'Corporate',
createdAt: 2018-03-26T18:49:27.955Z,
updatedAt: 2018-07-05T15:00:02.562Z,
id: '5ab940b71644750100261845' }
What I'd like it to look like:
{ memberOrganizations:
[ {
name: 'Tau Kappa Epsilon',
type: 'Greek - Fraternity',
institution: '5a3996d47bab3401001cc1bc',
id: '5a3ae7ebdfd69201001aa54d'
associatedVIPs:
[ { firstName: 'Irma',
lastName: 'Francisco',
email: 'irmaf#houstontransporter.com',
id: '5ae348da1ef63b245a74fe2d' },
{ firstName: 'Zach',
lastName: 'Cook',
email: 'zach#google.com',
id: '5ae348da1ef63b245a74f' } ]
},
{ name: 'Farmhouse',
type: 'Greek - Fraternity',
institution: '5a3996d47bab3401001cc1bc',
id: '5a4e71e806b97a01003bd313' } ],
name: 'Troy University',
createdAt: '2017-12-19T22:46:44.229Z',
updatedAt: '2018-07-05T15:18:03.182Z',
id: '5a3996d47bab3401001cc1bc' },
{ memberOrganizations:
[ { name: 'Alpha Epsilon Pi',
type: 'Greek - Fraternity',
institution: '5a4d534606b97a01003bd2f1',
id: '5a4f95c44ec7b6010025d2fb' },
{ name: 'Alpha Delta Chi',
type: 'Greek - Sorority',
institution: '5a4d534606b97a01003bd2f1',
id: '5a74a35e1981ef01001d0633' },
{ name: 'Phi Sigma Kappa',
type: 'Greek - Fraternity',
institution: '5a4d534606b97a01003bd2f1',
id: '5a7ba61821024e0100be67b7' } ],
name: 'University of Alabama',
createdAt: '2018-01-03T22:03:50.929Z',
updatedAt: '2018-07-05T15:18:03.182Z',
id: '5a4d534606b97a01003bd2f1' }

Normalizr: Identifying entities by type rather than schema for polymorphic mappings

For a polymorphic schema such as Union in Normalizr, for schema definitions and data:
const data = { owner: { id: 1, type: 'user', name: 'Anne' } };
const user = new schema.Entity('users');
const group = new schema.Entity('groups');
const unionSchema = new schema.Union({
user: user,
group: group
}, 'type');
const normalizedData = normalize(data, { owner: unionSchema });
normalized data takes the form:
{
entities: {
users: { '1': { id: 1, type: 'user', name: 'Anne' } }
},
result: { owner: { id: 1, schema: 'user' } }
}
The entities are keyed on the schema key, in this case, users, but the result object includes only the key for the schema in the UnionSchema definition. This can make it difficult to match up the elements later without full denormalization.
Is there some better way to normalize such data with normalizr to make it easier to pull the entity from the entities, given the result? For my purposes, ideally, data could be normalized from something like:
const data = { owner: { id: 1, type: 'users', name: 'Anne' } };
to
{
entities: {
users: { '1': { id: 1, type: 'users', name: 'Anne' } }
},
result: { owner: { id: 1, type: 'users' } }
}
Note that the type matches the entity key (that is pretty trivial), and the name of the key in result is type (more of a pain if you want to do it with more complex data). I suspect that that sort of normalization would make it harder to denormalize, but I'm interested in normalization only.
Got an answer on this:
https://github.com/paularmstrong/normalizr/issues/281
Apparently, the behavior is intentional and is not going to change--there is no way to use Normalizr to do what I asked.

Redux: local state id's and/or api uuid's

I'm using Redux with a REST api that uses UUID's. The usual pattern for storing state is using id's as a key for objects:
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
How would I use the UUID's from the api in this? I'd like to be able to create a new entity without having to request the UUID from the server first (for offline capabilities).
Should I:
Use local id's, keep the UUID in a _id property of the entity, and only use it when making an API request? This seems the easiest way, although it feels redundant and I will probably have to search through entities for a certain _id in some cases.
entities: {
articles: {
1: {
_id: 'UUID',
title: 'Some Article',
author: 1
},
2: {
id: 'UUID',
title: 'Other Article',
author: 1
}
},
users: {
1: {
_id: 'UUID',
name: 'Dan'
}
}
}
Use only UUID's from the API, and when creating a new item use a sort if temporary id until the API call is resolved? This seems the best way, although I'm not sure how I would go about changing the id's, which also feels wrong (as they're id's).
entities: {
articles: {
'UUID': {
_id: 'UUID',
title: 'Some Article',
author: 'UUID'
},
'UUID': {
_id: 'UUID',
title: 'Other Article',
author: 'creating'
}
},
users: {
'UUID': {
_id: 'UUID',
name: 'Dan'
},
'creating': {
name: 'Stan'
}
}
}
Do it some other way?
I wouldn't add it to the Redux store until the API returns a response.
In Vue, in my data for a given component I usually have two (sometimes more) root keys, one of which points to the part of my Redux store that handles the data, and the other that is usually form or something of that sort, and the Vue data changes due to binding.
After the user initiates the action to add the resource (POST /resources), and the server returns a successful response, I dispatch an action addedResource. And prior to that I'd dispatch something like addingResource, etc.
Is there any reason this wouldn't work? There shouldn't be a difference using an auto incremented, integer id field vs. a UUID. Your data normalization should still work the same way.

Categories

Resources