Neurelo API Reference (GraphQL)
Introduction
This API documentation is intended to provide an overview of how Neurelo generates APIs based on your data definition. It will go into detail on how to perform operations using a sample schema definition. You can then apply these concepts and patterns to your own schema. Reference documentation generated specifically for your data definition is included in your specific project on Neurelo's Data Access Platform.
Neurelo provides two types of APIs that are automatically generated and available for use.
The REST API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
The GraphQL API exposes a single endpoint where clients can send GraphQL queries or mutations and a strictly-typed schema that be be shared across consumers.
You can toggle between the GraphQL and REST API documentation when reviewing the documentation in the platform.
Reference - Neurelo Supported Databases and Versions
API Headers
Authentication
API calls to Neurelo are authenticated using an API Key for all API requests. This api key defines which environment the API request is interacting with. You can create an api key under the settings of the specific environment that you are trying to access. API Keys cannot be used across environments.
To utilize an api key, include it as a header with your API Request, using X-API-KEY
as the key.
Query Strategy
Neurelo generated APIs can be tuned to fetch data using either the selects
or joins
strategy. The main difference is that selects
executes multiple queries behind the scenes to gather the desired data, whereas joins
uses a single query when possible using database-level joins, to fetch the results.
By default, joins
strategy is enabled. This can be changed using an HTTP header. For example if you are using cURL, then to fetch all the users and their corresponding posts using selects
strategy:
Similarly, 'X-READ-STRATEGY: joins'
can be used.
joins
strategy is suitable for scenarios where you want to minimize the number of queries made to the database, especially when the relation expressions are relatively simpler, and there's less risk of data duplication.
selects
can be faster in scenarios with multiple many-to-many or one-to-many relations. This is because the database's flat record list from joins can sometimes contain a significant amount of repeated information. Despite joins' quick execution in the database, the process of moving and parsing this redundant data into JSON can incur high costs.
Query Viz
To review the database queries that Neurelo will be sending to your data source, you can use the X-QUERY-VIZ
HTTP header. For example, to enable query viz while fetching all the users and their corresponding posts:
This header will return both the query string and its corresponding query parameters.
Similarly, 'X-QUERY-VIZ: false'
can be used to disable the viz. By default, this header is disabled.
IMPORTANT: When query viz is enabled, the queries will still run against your selected environment, and they may modify data in that environment depending on your queries.
Operations
Creating Objects
You can create objects by utilizing one of two mutations available for creating objects. These are createOneObject
and createManyObject
, where Object
is the name of your object.
In this example, we will use a sample schema with a User object and a BlogPost object. A user has many posts, and a post has one user.
Create one User (CreateInput
)
CreateInput
)To create a single user, assuming that we have the sample schema running in an environment, we can issue a CreateOne
mutation, with the data argument set to the UserCreateInput
input type. For example:
The response from this insert request will look like this, which is the object that was inserted:
To prevent the insertion of records with unique fields or identifiers that already exist, we can use skipDuplicates
. For example:
The response from this insert request will look like this, which is the inserted object(s):
In the above example, as User IDs were same, the second record was prevented from being inserted.
NOTE: Currently, skipDuplicates
is not supported for MongoDB.
Creating multiple objects (CreateManyInput
)
CreateManyInput
)To create multiple users, assuming that we have the sample schema running in an environment, we can issue a CreateMany
mutation, with the data argument set to an array of UserCreateInput
types.
The response (AffectedRowsOutput
) from this insert request will look like this, which is the count of the inserted rows:
NOTE: Currently, related objects cannot be created or associated with the 'root' object using CreateManyInput
. To achieve this, it is necessary to use CreateInput
.
Creating with relations
Currently, Neurelo for MongoDB does not directly support the creation of objects with relations. However, you can create inner objects (which are equivalent to embedded documents, meaning documents nested within another document) or use references to accommodate your data modeling needs. Refer to the Modeling Relationships for MongoDB with Inner Objects and References section for more information.
When creating a single user, you can create or connect related object in the same transaction.
On an object with a has one relationship to another object, you can use the create
input to create a new related object automatically associated with the 'root' object. Alternatively, you can use the connect
input to link an existing related object to the 'root' object. When using connect
, an error will be thrown if the linked object is not found. To address this, use connectOrCreate
, which links an existing related object to the 'root' object or creates a new related object if it doesn't exist.
On an object with a has many relationship to another object, you can also utilize create
, connect
, and connectOrCreate
. Additionally, you can use createMany
to create many related objects.
create
create
To demonstrate creating a root object and its related object, we will use a sample schema with a User object and a BlogPost object. A user has many posts, and a post has one user.
The response from this insert request will look like this, which is the inserted object(s):
connect
connect
To create a root object and link it with an existing related object in a has many relationship, assuming that we have the sample schema running in an environment, we can use the connect
input.
The response from this insert request will look like this, which is the inserted object(s):
In the above example, the Post with an ID of 1 previously existed and is now being associated with a relationship with the new root object.
connectOrCreate
connectOrCreate
To create a root object and link it with an existing related object or create a new related object if it doesn't exist (when the root and related object are in a has many relationship), assuming that we have the sample schema running in an environment, we can use the connectOrCreate
input. For example,
The response from this insert request will look like this, which is the inserted object(s):
In the above example, by observing the Post's ID, we can conclude that the ID 3 was not found in the Post object. As a result, a new object was created.
createMany
createMany
To create a root object and link it with many related objects in a has many relationship, assuming that we have the sample schema running in an environment, we can use the createMany
input.
The response from this insert request will look like this, which is the inserted object(s):
Similar to createInput
, you can use skipDuplicates
in createMany
to prevent the insertion of records with unique fields or identifiers that already exist.
Retrieving Objects
You can retrieve objects by utilizing a few different queries that are generated for each object. There are three find queries available per object, they are findFirstObject
, findUniqueObject
and findManyObject
.
In this example, we will use a sample schema with a User object and a BlogPost object. A user has many posts, and a BlogPost has one user. A user has a relationship property to posts called posts
and the post has a relationship property to users called author
.
Retrieving unique object
To retrieve a unique user, assuming that we have the sample schema running in an environment, we can issue a query to findUniqueUser
with a where
argument that filters on unique properties. For example:
The response from this request will look like this, which is the retrieved object:
Retrieving all objects
To retrieve all users, assuming that we have the sample schema running in an environment, we can issue a query with findManyUser
. For example:
The response from this request will look like this, which is an array of the retrieved objects:
Filtering for specific objects
To filter specific objects, we can utilize the where
query argument. For complete documentation of all the options available to you with the query argument, take a look at the WhereInput
input type documentation below.
To filter for specific User objects, assuming that we have the sample schema running in an environment, we can issue a query with the where
argument set to the UserWhereInput
input type.
The response from this request will look like this, which is an array of the retrieved objects:
Retrieving related objects
To retrieve all users with their posts, assuming that we have the sample schema running in an environment, we can issue a query with findManyUser
. For example:
The response from this request will look like this, which is an array of the retrieved objects and their related objects:
Retrieving n-levels of related objects
Assume that in our sample schema, there is a new object Activity, such that each post has many activities. A post has a relationship property to activities called activity
.
To retrieve all the users, their post names, and activities on each post, assuming that we have the sample schema running in an environment, we can issue a query with findManyUser
. For example:
The response from this request will look like this, which is an array of the retrieved objects and their specific related objects:
Updating Objects
You can update objects by using one of two update mutations, these are similar to the create mutations, but include a where
argument to specify which objects should be updated. There are updateOneObject
and a updateManyObject
mutations available, Object
being replaced by the object that you are performing the update on.
Updating unique object (UpdateInput
)
UpdateInput
)Updating a unique object is similar to updating many, except that the where
argument is limited to filtering on unique properties. For example, the id
property on User is a unique property and is guaranteed to be unique to a single User object.
The response from this request will look like this, which is the updated object:
Updating multiple objects (UpdateManyInput
)
UpdateManyInput
)To update multiple users, we can utilize the updateManyObject
mutation with the data
and where
arguments to provide both our updated properties and a condition set to limit which objects are updated.
The response (AffectedRowsOutput
) from this update request will look like this, which is the count of the updated rows:
Updating scalars using special operations
push
push
When using the array
type for a property, the UpdateInput
provides a push
operation. This inserts a value or array of values at the end of the array. If the value is null, it would initialize the array with the value(s) provided. For example,
The response from this request will look like this, which is the updated object:
Updating with relations
Currently, Neurelo for MongoDB does not directly support the updation of objects with relations. However, you can update inner objects (which are equivalent to embedded documents, meaning documents nested within another document) or use references to accommodate your data modeling needs. Refer to the Modeling Relationships for MongoDB with Inner Objects and References section for more information.
When updating a single object, you can create, update, disconnect or delete related object in the same transaction.
On an object with a has one relationship to another object, you can use the update
input to update a related object automatically associated with the 'root' object. Alternatively, you can use the disconnect
input to unlink an existing related object with the 'root' object. When using update
, an error will be thrown if the linked object is not found. To address this, use upsert
, which updates an existing related object to the 'root' object or creates a new related object if it doesn't exist. You can also use delete
input to delete an existing related object.
The connect
, connectOrCreate
, and create
inputs (as explained in the Creating objects with relations section) are also supported here.
On an object with a has many relationship to another object, you can also utilize create
, connect
, connectOrCreate
, update
, upsert
, delete
, and disconnect
inputs. Additionally, you can use createMany
, updateMany
, and deleteMany
to create, update, and delete many related objects, respectively.
createMany
is explained in the Creating objects with relations section.
update
update
To demonstrate updating a root object and its related object, we will use a sample schema with a User object and a BlogPost object. A user has many posts, and a post has one user.
The response from this update request will look like this, which shows the updated object(s):
In the above example, the Post with an ID of 2 previously existed and is now being updated along with the name of the user.
upsert
upsert
To update a root object and update its corresponding related object or create a new related object if it doesn't exist (when the root and related object are in a has many relationship), assuming that we have the sample schema running in an environment, we can use the upsert
input. For example,
The response from this upsert request will look like this, which is the upsert object(s):
disconnect
disconnect
To unlink an existing related object with the 'root' object (when the root and related object are in a has many relationship), assuming that we have the sample schema running in an environment, we can use the disconnect
input. For example,
The response from this request will look like this, which is the updated object(s):
In the above example, the Post with an ID of 2 previously existed and still exists, but it is now being unlinked with respect to the 'root' object. Furthermore, the name of the user also gets updated.
delete
delete
To delete an existing related object asccociated with a 'root' object (when the root and related object are in a has many relationship), assuming that we have the sample schema running in an environment, we can use the delete
input. For example,
The response from this request will look like this, which is the updated object(s):
In the above example, the Post with an ID of 2 is now deleted. Furthermore, the name of the user also gets updated.
updateMany
updateMany
To update a root object and its many related objects in a has many relationship, assuming that we have the sample schema running in an environment, we can use the updateMany
input.
The response from this updateMany request will look like this, which is the updated object(s):
deleteMany
deleteMany
To update a root object and delete its many related objects in a has many relationship, assuming that we have the sample schema running in an environment, we can use the deleteMany
input.
The response from this deleteMany request will look like this, which is the deleted object(s):
Deleting Objects
You can delete objects by utilizing one of two mutations. These mutations are deleteOneObject
and a deleteManyObject
mutations available, where Object
is the name of the object that you are deleting.
In this example, we will use a sample schema with a User object.
Delete unique object
To delete a unique user, assuming that we have the sample schema running in an environment, we can issue a query to deleteOneUser
. For example:
The response from this request will look like this, which is the deleted object:
Delete all objects
To delete all users, you can issue a deleteManyUser
mutation with arguments present. For example:
The response from this request will look like this, which is the count of the deleted object(s):
Delete specific objects
To delete specific objects, we can utilize the where
argument. For complete documentation of all the options available to you with the query argument, take a look at the WhereInput
input type documentation below.
To retrieve all specific, we can issue deleteManyUser
with the where argument specified. For example:
The response from this request will look like this, which is the count of the deleted object(s):
Aggregating Objects
You can aggregate objects by utilizing the aggregateObject
query that is generated for each object. The following aggregate functions are supported: _count
, _sum
, _avg
, _min
, and _max
.
In this example, we will use a sample schema with a Post object.
Aggregating specific objects
To aggregate post objects, assuming that we have the sample schema running in an environment, we can issue a query with aggregatePost
. For example, to average the number of words for post objects:
The response (AggregateOutput
) from this request will look like this, which contains the aggregated value:
Aggregating all objects
Presently, only _count
function supports aggregating all objects.
To count all objects, assuming that we have the sample schema running in an environment, we can issue a query with aggregatePost
with the _count
function and _all
value specified for it. For example,
The response (AggregateOutput
) from this request will look like this, which contains the aggregated value:
Grouping Objects
In this example, we will use a sample schema with a User object.
You can group by objects by utilizing the groupByObject
query that is generated for each object. It is mandatory to include a by
option to group records by one or more fields. This option takes an array of field names (Array
), to specify the fields to group by with.
For example, to count the number of users by country:
The response from this request will look like this, which is the grouped and aggregated object(s):
Group By with Filtering
To filter the fields before grouping, we can utilize the where
option. For example,
The response from this request will look like this, which is the grouped and aggregated object:
To filter the groups by aggregate functions, we can utilize the having
option.
The response from this request will look like this, which is the grouped and aggregated object(s):
Input Types
In this section, we’ll take a look at some arguments that apply to many different operations. The avaliability of each argument is dependent on the operation being performed, for example, the WhereInput
argument is not available on Insert operations.
Once you are familiar with these arguments, we hope that utilizing individual operations on your objects comes naturally and will not require continous referral to the generated reference documentation.
where
(WhereInput
)
where
(WhereInput
)The WhereInput
argument allows you to add conditions to your query. This argument can be used when retrieving objects, as well as when updating objects where it will act as the condition on which objects are updated.
Filtering with Scalars
Each scalar has it’s own set of operations that can be performed to assert a condition, for example, an integer has the following operators available to it: equals
, not
, in
, notIn
, lt
, lte
, gt
, gte
. With the exception of in
and notIn
, all of these operators will accept the matching scalar, in
and notIn
will take an array of the matching scalar.
Here is a list of all available operators: equals
, not
, in
, notIn
, lt
, lte
, gt
, gte
, contains
, startsWith
, and endsWith
. The availiblity of these is dependant on the scalar type, for example, you cannot utilize the gt
operator on a string.
A where condition for a given object includes all of the scalars present on the object with their respective scalar filter type. To construct a where condition utilizing only an object’s scalar properties, you can use the name of the property as the key, and then a where object for that specific scalar type.
Here is a more comprehensive overview of these operators:
Operator
Description
Example
equals
Filter for field values equal to a specific value
To filter when age
equals 21, { age: { equals: 21 } }
lt/lte
Filter for field values "less than / less than or equal to" a specific value
To filter when age
is less than 21, { age: { lt: 21 } }
gt/gte
Filter for field values "greater than / greater than or equal to" a specific value
To filter when age
is greater than or equal to 30, { age: { gte: 30 } }
not
Filters when field value does not equal a specific value
To filter records that have all ids except 100
, {id: {not: 100}}
in/notIn
Checks if a field value exists / does not exist in a list, and filters accordingly.
To filter records having ids as either 1
, 3
or 6
, { id: { in: [1, 3, 6] } }
startsWith/endsWith
Filter when a specific value is at the start or end of a field value. Case-sensitive by default. _
wildcard can be used to match one or more characters. $
wildcard can be used to match zero or more characters.
To filter names that start with "Ron" (case-insensitive), {name: {startsWith: "Ron", mode: "insensitive"} }
. To filter names that start with "R", followed by one or more characters, and then "d", {name: {startsWith: "R_d"} }
. This matches names such as "Roland" and "Rudd".
contains
Filters when a specific value is contained in a field value. Case-sensitive by default. _
wildcard can be used to match one or more characters. $
wildcard can be used to match zero or more characters.
To filter country names that contain the word "United", {country: {contains: "United" } }
search
Filters using full-text search capabilities. This operator is specific to strings and currently, it is not supported with MongoDB. Currently, this operator is not supported with MongoDB. For querying, PostgreSQL and MySQL's native full-text search capabilities are leveraged. For example, in Postgres, &
can be used to perform a boolean AND on two strings. Similarly, |
and !
can be used to perform boolean OR and boolean NOT, respectively. For MySQL, +
and -
are used as boolean AND and boolean NOT, respectively. Boolean OR in MySQL is represented using no operators; for example, Tomato Orange
would check if the text contains Tomato
or Orange
.
In PostgreSQL, to filter records with the engine as Firefox or Chrome, use {engine: {search: "Firefox | Chrome"}}
. In MySQL, to filter records with Firefox but not Chrome in the report, use {report: {search: "+Firefox -Chrome"}}
.
Combining conditions
When you add conditions to a WhereInput
object, you are asserting that all of the listed conditions must evaluate to true for an object to be returned, but you are also able to further customize your query’s condition by utilizing the AND
, OR
, and NOT
properties. All of these properties accept an array of the object’s WhereInput type, allowing you to nest and compose different filtering conditions to construct your query.
Here is a more comprehensive overview of these operators:
Operator
Description
Example
OR
Filters for field values when one or more conditions is true
To filter names starting with either "A" or "B", {OR: [{name: {startsWith: "A"}}, {name: {startsWith: "B"}}]}
. Furthermore, to filter names starting with "A" or ending with "n", {OR: [{name: {startsWith: "A"}}, {name: endsWith: "n"}]}
.
AND
Filters for field values when all conditions are true
To filter for first names starting with "A" and last names ending with "n", {AND: [{firstName: {startsWith: "A"}}, {lastName: {endsWith: "n"}}]}
. Furthermore, to filter names starting with "B" and ending with "n", we can use operators such as startsWith
and endsWith
in a single object itself, like {AND: [{name: {startsWith: "B", endsWith: "n"}}]}
.
NOT
Filters for field values when all the conditions are false
To filter for names that are not "Alan" and not "George", {NOT: [{name: {equals: "Alan"}}, {name: {equals: "George"}}]}
. Furthermore, to filter names not starting with "C" and not ending with "n", we can use operators such as startsWith
and endsWith
in a single object itself, like {NOT: [{name: {startsWith: "C", endsWith: "n"}}]}
.
Note on Scope of Logical operators:
Implicit AND: Combining conditions within one object,
{name: {startsWith: "A", endsWith: "n"}}
, uses an implicitAND
logic, meaning all conditions must be met.Explicit Logical Operators: Using
OR
,AND
, orNOT
to combine multiple conditions, such as{OR: [ {...}, {...} ]}
, processes each condition in its own scope before applying the logical operator. This structure allows for complex filtering, evaluating from the inner-most conditions outwards.
Furthermore, you can combine these operators to do more powerful filtering. For example,
NOT
andAND
: To filter for names that do no start with "A" and end with "n",{NOT: {AND: [{name: {startsWith: "A"}}, {name: {endsWith: "n"}}]}}
.OR
andAND
: To filter for ids that are between 0 to 10 or 30 to 40,{OR: [{AND: [{id: {gte: 0}}, {id: {lte: 10}}]}, {AND: [{id: {gte: 30}}, {id: {lte: 40}}]}]}
.
Filtering with List
You can use the following operators to perform filtering with lists: has
, hasSome
, hasEvery
, and isEmpty
.
Additionally, you can employ the equals
operator introduced earlier.
Here is a more comprehensive overview of these operators:
Operator
Description
Example
has
Filters for lists where a given value exists.
To filter when Canada
is in a locations
list, {locations: {has: "Canada"}}
hasSome
Filters for lists where at least one value from the search list exists.
To filter when Canada
or United States
are in a locations
list, {locations: {hasSome: ["Canada", "United States"]}}
hasEvery
Filters for lists where all values from the search list exists.
To filter when Canada
, United States
, and Spain
are in a locations
list, {locations: {hasEvery: ["Canada", "United States", "Spain"]}}
isEmpty
Filters for empty lists.
To filter for empty locations
list, {locations: {isEmpty: true}}
. Similarly, to filter for non-empty lists, use {isEmpty: false}
.
Filtering with JSON
You can use the following operators to perform JSON filtering: array_starts_with
, array_ends_with
, array_contains
, string_starts_with
, string_ends_with
, and string_contains
.
Additionally, you can employ operators introduced earlier, such as equals
, gt
, gte
, lt
, lte
, and not
.
To filter a specific part of the JSON object, each of these operators requires a specified path
. For example, consider a JSON object like {Produce: {Fruits: {Organic: ["Orange", "Mango", "Banana"], NonOrganic: ["Apple", "Melon"]}}}
. In Postgres, the path Produce -> Fruits -> Organic
can be represented as ["Produce", "Fruits", "Organic"]
. Similarly, for MySQL, it can be represented as '$.Produce.Fruits.Organic'
.
Here is a more comprehensive overview of these operators (all the paths are specific to Postgres):
Operator
Description
Example
array_starts_with
Filters for JSON objects where a specified path has a list that begins with a specific value.
To filter when the list at ["Fruits", "Organic"]
path starts with Orange
, {Crops: {path: ["Fruits", "Organic"], array_starts_with: "Orange"}}
array_ends_with
Filters for JSON objects where a specified path has a list that ends with a specific value.
To filter when the list at ["Fruits", "Organic"]
path ends with Apple
, {Crops: {path: ["Fruits", "Organic"], array_starts_with: "Apple"}}
array_contains
Filters for JSON objects where a specified path has a list that contains a specific value.
To filter when the list at ["Schedule", "Heathrow"]
path contains 9 , {Misc: {path: ["Schedule", "Heathrow"], array_contains: 9}}
string_starts_with
Filters for JSON objects where a specified path has a string that begins with a specific value.
To filter when the string at ["Premium Customers", "NYC", "George"]
path starts with Q2F0cw==
, {IDs: {path: ["Premium Customers", "NYC", "George"], string_starts_with: "Q2F0cw=="}}
string_ends_with
Filters for JSON objects where a specified path has a string that ends with a specific value.
To filter when the string at ["Premium Customers", "NYC", "George"]
path ends with TmV1cmVsbw==
, {IDs: {path: ["Premium Customers", "NYC", "George"], string_ends_with: "TmV1cmVsbw=="}}
string_contains
Filters for JSON objects where a specified path has a string that contains a specific value.
To filter when the string at ["FullReport", "Browser"]
path contains Firefox
, {Details: {path: ["FullReport", "Browser"], string_contains: "Firefox"}}
Filtering with Relations
You are able to utilize related objects in a condition too, though the manner in which you do so will depend on the type of relationship that this object has with it’s related object.
When a relationship has one of another object, you can utilize the is
and isNot
filters to construct conditions on a related object. For example, if we have a Post object, which has one User object, we can create a condition utilizing the User’s objects properties like so: { user: { is: { name: { equal: "George" } } } }
. This filter would return all Post objects where the related User’s name is equal to George.
When a relationship has many of another object, you can utilize the some
, every
, and none
conditions to construct conditions on a set of related objects. For example, if we have a User object that has many Posts, we can create a condition utilizing the Post’s objects properties like so:{ posts: some: [ { title: { equal: "Cats" } } ] }
. This will return a list of users where at least one of their posts has the title of “Cats”.
Here is a more comprehensive overview of these operators:
Operator
Description
Example
is
Filters a record when related record "is" equal to the filter condition. Can only be used when a relationship has one of another object.
If every user has one post, to filter when name equals Alan, { user: { is: { name: { equal: "Alan" } } } }
isNot
Filters a record when related record "is not" equal to the filter condition. Can only be used when a relationship has one of another object.
If every user has one post, to filter when name does not start with "A", { user: { isNot: { name: { startsWith: "A" } } } }
some
Filters a record when related record has "some" filter conditions as true. Can only be used when a relationship has many of another object.
If a brand has many sauces, to find out brands that have "Paprika" in some of their sauces, { sauces: { some: [ { ingr: { contains: "paprika" } } ] } }
every
Filters a record when related record has "every" filter conditions as true. Can only be used when a relationship has many of another object.
If a brand has many sauces, to find out brands that have "Paprika" in all of their sauces, { sauces: { every: [ { ingr: { contains: "paprika" } } ] } }
none
Filters a record when related record has "none" of its filter conditions as true. Can only be used when a relationship has many of another object.
If a brand has many sauces, to find out brands that do not have "Paprika" in any of their sauces, { sauces: { none: [ { ingr: { contains: "paprika" } } ] } }
Note: You can combine the three sections above to construct complex queries.
order_by
(OrderByWithRelationInput
)
order_by
(OrderByWithRelationInput
)The orderBy
argument takes an array of objects, with the following definition:
{ [key: ScalarName]: "asc" | "desc" }
You can use any scalar on the object being queried as a key, along with the direction of the sort as the value in the object. Our GraphQL APIs support ordering of nested fields.
For example, given a sample schema with a User object:
The response from this request will look like this:
skip
& take
skip
& take
Pagination with Neurelo’s APIs works using the skip
and take
options as an implementation of offset based pagination. You can pass an integer to each option to limit or skip the resulting objects.
For example, given a sample schema with a User object, to skip one record and take the next record:
The response from this request will look like this:
by
by
The by
option takes an array of field names (Array
), to specify the fields to group by with. It must be ensured that every selected scalar field in your graphql body that is not part of an aggregation must be included in by
option's array of field names.
For example, let us use a sample schema with a User object,
The response from this request will look like this:
having
(HavingInput
)
having
(HavingInput
)having
option is used in conjuction with by
option to filter the groups by aggregate functions. It is a special kind of where
which accepts all the where
options, together with the ability to filter aggregate functions.
To filter by aggregate function, the following definition can be used:
{ [field: ScalarName]: { [key: aggregateFunction]: whereCondition } }
Supported aggregate functions are: _count
, _sum
, _avg
, _min
, and _max
. whereCondition is the same as a where
body and accepts all the where
options.
For example, let us use a sample schema with a Post object,
The response from this request will look like this, which is the grouped and aggregated object(s):
Furthermore, similar to filter
, you can use AND
, OR
, and NOT
operators to do more powerful filtering. For example, to filter when the number of words is between 1000 and 10000, you can use {"OR": [{"id": {"_sum": {"gte": 1000}}}, {"id": {"_sum": {"lte": 10000}}}]}
.
cursor
cursor
cursor
option is used to retrieve results before or after a specified cursor. This cursor is a unique identifier or a combination of unique identifiers.
Implicitly an ordering is performed based on the unique identifiers specified in the cursor, to ensure a consistent and predictable sequence of results.
For example, let us consider a sample schema with a User object. To fetch all users with IDs less than or equal to 2, the following can be used:
The response from this request will look like this:
Furthermore, to fetch the user after skipping two users, starting from ID 3, we can use the following:
The response from this request will look like this:
In the above example, User IDs 3 and 4 were skipped, and the result set of User ID 5 was returned.
NOTE: Currently, the REST APIs do not have an equivalent functionality. As a workaround, use order_by
to sort the primary keys, followed by filter
to exclude the primary keys. For instance, cursor: { id: 3 }
would have an equivalent of order_by=[{"id": "asc"}]
with filter={"id": {"gte": 3}}
.
Modeling Relationships for MongoDB with Inner Objects and References
Currently, Neurelo for MongoDB doesn't support direct manipulation of objects with relations. However, you can work with inner objects (equivalent to embedded documents, i.e., documents nested within another document) or use references to model such relationships.
To decide which data modeling approach suits your needs best, refer to our guide on how to work with embedded documents and references in MongoDB.
In summary, inner objects enhance read performance by reducing database queries and ensuring atomic updates within a single document. They are optimal for closely related data that is frequently accessed together, remains relatively static, and adheres to the 16MB document size limit. However, they might lead to data redundancy and scalability challenges as your database grows.
On the other hand, references are more suitable for large or frequently changing data. They excel in many-to-many relationships by offering the flexibility to link documents across different collections, preventing data duplication and maintaining database normalization. The trade-off, however, is the need for additional queries to get related data, which could affect your performance.
Inner Objects
Neurelo supports the management of inner objects at the schema level. To learn how to create inner objects for your schema, please refer to the Neurelo Schema Language reference.
Now, assume that will have a sample schema with a User object and an Address inner object. A user has one address. For example,
Create
To create a single user with its address, assuming that we have the sample schema running in an environment, we can issue a CreateOne
mutation, with the data argument set to the userCreateInput
input type. For example:
Note that, at present, our APIs do not allow the user to auto generate inner object ids, hence we had to manually specify it in the above examples.
The response from this insert request will look like this, which is the object that was inserted:
To create multiple users with their address, we can issue a CreateMany
mutation, with the data argument set to an array of userCreateInput
types.
The response (AffectedRowsOutput
) from this insert request will look like this, which is the count of the inserted rows:
Retrieve
To retrieve a unique user with its address, assuming that we have the sample schema running in an environment, we can issue a query to findUniqueUser
with a where
argument that filters on unique properties. For example:
The response from this request will look like this, which is the retrieved object:
Similarly, to retrieve all users with their address, assuming that we have the sample schema running in an environment, we can issue a query with findManyuser
. For example:
The response from this request will look like this, which is an array of the retrieved objects (with their inner objects):
Update
To update multiple users with their address, we can utilize the updateManyObject
mutation with the data
and where
arguments to provide both our updated properties and a condition set to limit which objects are updated.
The response (AffectedRowsOutput
) from this update request will look like this, which is the count of the updated rows:
Delete
To delete specific users with their address, you can issue a deleteOneuser
mutation with arguments present. For example:
The response from this request will look like this, which is the deleted object:
Note that this will delete both the object and its inner object. To remove the contents of just the inner object, you can use the UPDATE request with an unset
:
This approach requires setting the inner object of your schema, specifically the unique ID, to have nullable
set to true
.
API Errors
Errors for the API calls will be presented in a list format so that multiple issues can be communicated at once. Each error object will contain an errors
property that contains the error message and the location of the error.
Two types of errors can be returned as a response:
Validation errors - request is invalid or contains invalid data
Execution errors - request execution failed
For example, a sample schema and a sample request like:
Will generate the following response:
The above example contains two errors, each with an error message and the specific location of the invalid attribute in the details section. The location parameter contains a JSON path to the attribute that failed the validation.
Last updated