Multiple connections in same fragment using usePaginationFragment - relayjs

Looking through the doc https://relay.dev/docs/guided-tour/list-data/advanced-pagination/ looks like it is possible to have multiple connections in the same component but in different fragments.
For my use case, I need to have multiple connections in the same fragment. Example what I have in mind:
fragment Component_viewer on Viewer
#refetchable(queryName: "ComponentRefetchQuery") {
myConnection1 #connection(key: "Component_myConnection1") {
totalResults
...ComponentThatHandlesConnection_myConnection1
}
myConnection2 #connection(key: "Component_myConnection2") {
totalResults
...ComponentThatHandlesConnection_myConnection2
}
}
The reason why I need this functionality is that I need the data of totalResults field above the connection component in the component tree. Is this possible to achieve with usePaginationFragment? Or maybe there is a better way to achieve this?

I've implemented it like so, we spread the first fragment on a query and then second fragment on the first fragment.

Related

How to filter _source in reactivesearch?

I need to exclude certain fields from the _source field in the elastic response since those fields are huge and transferring them unnecessarily wastes lots of time. In general, in elastic this is done by providing _source parameter in the query, e.g.:
GET /_search
{
"_source": { "excludes": [ "content" ] },
"query" : { ... }
}
Searchkit, for example, does this exclusion for highlighted fields automatically (which would be ideal in my case), but also supports an option for user to provide _source filter irrespective of highlighting too. Reactivesearch DataSearch component seems to be missing this kind of capability.
I can't figure out how to add _source (or any other search parameter) to the reactivesearch DataSearch query. Is that possible?
We currently don't support this behavior in ReactiveSearch, but we should. I have filed an issue for the same https://github.com/appbaseio/reactivesearch/issues/417.
Edit: This is now supported, you can see how to pass it in the documentation of Result components.

Relationship between GraphQL and database when using connection and pagination?

It is very easy to set up pagination with Relay however there's a small detail that is unclear to me.
both of the relevant parts in my code are marked with comments, other code is for additional context.
const postType = new GraphQLObjectType({
name: 'Post',
fields: () => ({
id: globalIdField('Post'),
title: {
type: GraphQLString
},
}),
interfaces: [nodeInterface],
})
const userType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: globalIdField('User'),
email: {
type: GraphQLString
},
posts: {
type: postConnection,
args: connectionArgs,
resolve: async (user, args) => {
// getUserPosts() is in next code block -> it gets the data from db
// I pass args (e.g "first", "after" etc) and user id (to get only user posts)
const posts = await getUserPosts(args, user._id)
return connectionFromArray(posts, args)
}
},
}),
interfaces: [nodeInterface],
})
const {connectionType: postConnection} =
connectionDefinitions({name: 'Post', nodeType: postType})
exports.getUserPosts = async (args, userId) => {
try {
// using MongoDB and Mongoose but question is relevant with every db
// .limit() -> how many posts to return
const posts = await Post.find({author: userId}).limit(args.first).exec()
return posts
} catch (err) {
return err
}
}
Cause of my confusion:
If I pass the first argument and use it in db query to limit returned results, hasNextPage is always false. This is efficient but it breaks hasNextPage (hasPreviousPage if you use last)
If I don't pass the first argument and don't use it in db query to limit returned results, hasNextPage is working as expected but it will return all the items I queried (could be thousands)
Even if database is on same machine (which isn't the case for bigger apps), this seems very, very, very inefficient and awful. Please prove me that Im wrong!
As far as I know, GraphQL doesn't have any server-side caching therefore there wouldn't be any point to return all the results (even if it did, users don't browse 100% content)
What's the logic here?
One solution that comes to my mind is to add +1 to first value in getUserPosts, it will retrieve one excess item and hasNextPage would probably work. But this feels like a hack and there's always excess item returned - it would grow relatively quickly if there are many connections and requests.
Are we expected to hack it like that? Is it expected the return all the results?
Or did I misunderstand the whole relationship between database and GrahpQL / Relay?
What if I used FB DataLoader and Redis? Would that change anything about that logic?
Cause of my confusion
The utility function connectionFromArray of graphql-relay-js library is NOT the solution to all kinds of pagination needs. We need to adapt our approach based on our preferred pagination models.
connectionFromArray function derives the values of hasNextPage and hasPrevisousPage from the given array. So, what you observed and mentioned in "Cause of my confusion" is the expected behavior.
As for your confusion whether to load all data or not, it depends on the problem at hand. Loading all items may make sense in several situations such as:
the number of items is small and you can afford the memory required to store those items.
the items are frequently requested and you need to cache them for faster access.
Two common pagination models are numbered pages and infinite scrolling. The GraphQL connection specification is not opinionated about pagination model and allows both of them.
For numbered pages, you can use an extra field totalPost in your GraphQL type, which can be used to display links to numbered pages on your UI. On the back-end, you can use feature like skip to fetch only the needed items. The field totalPost and the current page number eliminates the dependency on hasNextPage or hasPreviousPage.
For infinite scrolling, you can use the cursor field, which can be used as the value for after in your query. On the back-end, you can use the value of cursor to retrieve the next items (value of first). See an example of using cursor in Relay documention on GraphQL connection. See this answer about GraphQL connection and cursor. See this and this blog posts, which will help you better understand the idea of cursor.
What's the logic here?
Are we expected to hack it like that?
No, ideally we're not expected to hack and forget about it. That will leave technical debt in the project, which is likely to cause more problems in the long term. You may consider implementing your own function to return a connection object. You will get ideas of how to do that in the implementation of array-connection in graphql-relay-js.
Is it expected the return all the results?
Again, depends on the problem.
What if I used FB DataLoader and Redis? Would that change anything about that logic?
You can use facebook dataloader library to cache and batch-process your queries. Redis is another option for caching the results. If you load (1) all items using dataloader or store all items in Redis and (2) the items are lightweight, you can easily create an array of all items (following KISS principle). If the items are heavy-weight, creating the array may be an expensive operation.

Grails get domain properties

I'm trying to accelerate the performance of my app and wonder if there is a difference between accessing domain property value with instance.name and instance.getName()
If it is, which one is the best in terms of performance ?
Example
class User {
String name
}
User user = User.get(100);
//is it better this way
user.name
//or this way
user.getName()
Thank you
It doesn't matter for the usage you've provided, because user.name uses user.getName() behind scenes. So it's the same. If you want to access property directly you have to use # like this user.#name. See more here
But I don't think this is the way you can speed up your app.
It is very likely you will find a lot easier ways for improving performance of your code. Here are some ideas where to start if you like to improve performance.
A) Number of queries. Try to avoid the the N+1 problem. For example if one user hasMany [events: Event], code like user.events.each { access event.anyPropertyExceptId } will dispatch new queries for each event.
B) Efficiency of queries. Grails per default creates indexes for all gorm associations / other nested domains. However anything you use to search, filter etc. you need to do "manually" for example.
static mapping = {
anyDomainProperty index: 'customIndexName'
}
C) Only query for the data you are interested in, replace for example:
User.all.each { user ->
println user.events.size()
}
with
Event.withCriteria {
projections {
property('user')
countDistinct('id')
groupProperty('user')
}
}
D) If you really need to speed up your groovy code and your problem is rather a single request than general cpu usage, take a look at http://gpars.codehaus.org and http://grails.org/doc/2.3.8/guide/async.html and try to parallize work.
I doubt any performance issues in your application are related to how you are accessing your properties of your domain classes. In fact, if you profile/measure your application I'm sure you will see that is the case.

JQGrid and .NET MVC - Load Search Results

Ok, I am new at jQuery, but the JQGrid has peaked my interest. While implementing the grid, I have come across two problems that I am not sure how to solve. Both involve loading the grid with results.
How do you load the grid when you have parameters in your route. For instance, http://domain.com/search/results/2010/KY...I am wanting all results matching 2010 in Kentucky. In the javascript section of the grid initialization, I need to supply a URL (such as /search/gridResults/). How does one pass the other route values or at least use them to load the grid.
Same question, but more along the lines of when the page is loaded with posted form values from a search form.
Perhaps the URL is mostly to do with AJAX-y functions. It would be nice to sort and page with AJAX but to load the grid with AJAX is not neccessary.
Sorry for the long post, but I am sure others have faced this problem even though Google tells me otherwise :) PS - I have looked at Phil Haacks (sp?) and Craig something's blogs about using JQGrid, but neither touch upon loading pre-determined search results.
You can specify that directly with the 'url' key. e.g.: /search/gridResults/2010/KY
I actually use a custom javascript method in the postData jqgrid key for this (which you could use to solve your question 1 depending on the situation). This seemed kind of lame to me that I had to write this method, but I found something on the internet and had to keep hacking on it to make it flexible enough for my uses.
Code for custom method below. It reads params from the url directly. For POST params, you would need to do something else obviously, but to get them to jqgrid, it's the same idea:
// Read a page's GET URL variables and return them as an associative array.
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(
window.location.href.indexOf('?') + 1
).split('&');
for(var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
if (hash.length == 2) {
vars.push(hash[0]);
vars[hash[0]] = decodeURIComponent(hash[1].replace("+", "%20"));
}
}
return vars;
}
Hopefully that helps... If you come up with something better, I'd love to hear it. :)

Repository Interface - Available Functions & Filtering Output

I've got a repository using LINQ for modelling the data that has a whole bunch of functions for getting data out. A very common way of getting data out is for things such as drop down lists. These drop down lists can vary. If we're creating something we usually have a drop down list with all entries of a certain type, which means I need a function available which filters by the type of entity. We also have pages to filter data, the drop down lists only contain entries that currently are used, so I need a filter that requires used entries. This means there are six different queries to get the same type of data out.
The problem with defining a function for each of these is that there'd be six functions at least for every type of output, all in one repository. It gets very large, very quick. Here's something like I was planning to do:
public IEnumerable<Supplier> ListSuppliers(bool areInUse, bool includeAllOption, int contractTypeID)
{
if (areInUse && includeAllOption)
{
}
else if (areInUse)
{
}
else if (includeAllOption)
{
}
}
Although "areInUse" doesn't seem very English friendly, I'm not brilliant with naming. As you can see, logic resides in my data access layer (repository) which isn't friendly. I could define separate functions but as I say, it grows quite quick.
Could anyone recommend a good solution?
NOTE: I use LINQ for entities only, I don't use it to query. Please don't ask, it's a constraint on the system not specified by me. If I had the choice, I'd use LINQ, but I don't unfortunately.
Have your method take a Func<Supplier,bool> which can be used in Where clause so that you can pass it in any type of filter than you would like to construct. You can use a PredicateBuilder to construct arbitrarily complex functions based on boolean operations.
public IEnumerable<Supplier> ListSuppliers( Func<Supplier,bool> filter )
{
return this.DataContext.Suppliers.Where( filter );
}
var filter = PredicateBuilder.False<Supplier>();
filter = filter.Or( s => s.IsInUse ).Or( s => s.ContractTypeID == 3 );
var suppliers = repository.ListSuppliers( filter );
You can implement
IEnumerable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will retrieve all suppliers from the database that are then filtered using LINQ.
Assuming you are using LINQ to SQL you can also implement
IQueryable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will only retrieve the necessary suppliers from the database when the collection is enumerated. This is very powerful and there are also some limits to the LINQ you can use. However, the biggest problem is that you are able to drill right through your data-access layer and into the database using LINQ.
A query like
var query = from supplier in repository.GetAllSuppliers()
where suppliers.Name.StartsWith("Foo") select supplier;
will map into SQL similar to this when it is enumerated
SELECT ... WHERE Name LIKE 'Foo%'

Resources