How to project nested documents along side properties in the root document? - elasticsearch

I am attempting to return a projection of a nested document and some properties from the root document also. I would like to do this within the query if at all possible.
For example, I have an index cities where and the initial dataset:
[
{
_id: "1",
city: "New York"
state:"NY"
users: [
{
firstName: "John",
lastname: "Peters",
birthYear: 1985
}, {
firstName: "Raul",
lastname: "Other",
birthYear: 1986
}, {
firstName: "Paul",
lastname: "Ray",
birthYear: 1997
}
]
},
{
_id: "2",
city: "Hackensack",
state: "NJ"
users: [
{
firstName: "Joe",
lastname: "Anders",
birthYear: 1988
}
]
},
{
_id: "3",
city: "Albany"
state:"NY"
users: [
{
firstName: "Zoy",
lastname: "Bat",
birthYear: 1984
}, {
firstName: "Ana",
lastname: "Lily",
birthYear: 1999
}
]
}
]
users is of type nested. (S/n: I think this is for the best currently because I would like to possibly filter on one of the properties, but I am willing to change this if need be.)
I would like to do a query for users in the state of NY ordered by birthYear, and what I would like Elasticsearch to return is something like:
[
{
city: "Albany"
firstName: "Zoy",
lastname: "Bat",
birthYear: 1984
}, {
city: "New York"
firstName: "John",
lastname: "Peters",
birthYear: 1985
}, {
city: "New York"
firstName: "Raul",
lastname: "Other",
birthYear: 1986
}, {
city: "New York"
firstName: "Paul",
lastname: "Ray",
birthYear: 1997
}, {
city: "Albany"
firstName: "Ana",
lastname: "Lily",
birthYear: 1999
}
]
This feels like something that should be possible during query time but I have not been able to find the appropriate functionality.

It is not possible to return what you expect using nested documents, as you cannot mix and match documents nested into different top-level documents and return them in the order you mention.
You should actually denormalize your data and promote users to primary entities. First, that would easily solve the query need you expressed and second I'm pretty confident this would also support your other needs.
So your documents should look like this instead:
{
id": 1,
firstName: "John",
lastname: "Peters",
birthYear: 1985,
city: "New York",
state:"NY"
}
{
id": 2,
firstName: "Raul",
lastname: "Other",
birthYear: 1986,
city: "New York",
state:"NY"
}
etc...

Related

Dgraph data is not accessible via graphql if added via DQL mutation

What I want to do
Add data using DQL mutation https://github.com/dgraph-io/dgo#running-a-mutation and these data to also be visible via graphql.
Dgraph version: v21.03.2
DQL schema:
<Product.created_at>: datetime .
<Product.image>: string .
<Product.name>: string #index(hash) #upsert .
<Product.slug>: string #index(hash) #upsert .
<Product.updated_at>: datetime .
<dgraph.drop.op>: string .
<dgraph.graphql.p_query>: string #index(sha256) .
<dgraph.graphql.schema>: string .
<dgraph.graphql.xid>: string #index(exact) #upsert .
type <Product> {
Product.name
Product.slug
Product.image
Product.created_at
Product.updated_at
}
type <dgraph.graphql> {
dgraph.graphql.schema
dgraph.graphql.xid
}
type <dgraph.graphql.persisted_query> {
dgraph.graphql.p_query
}
GraphQL schema:
type Product {
id: ID!
name: String! #id #dgraph(pred: "Product.name")
slug: String! #id #dgraph(pred: "Product.slug")
image: String #dgraph(pred: "Product.image")
created_at: DateTime! #dgraph(pred: "Product.created_at")
updated_at: DateTime! #dgraph(pred: "Product.updated_at")
}
Using the above schema, graphql queries are working fine.
Graphql mutation
mutation MyMutation {
addProduct(input: {name: "product 1", slug: "prod-1", created_at: "2021-10-04T06:37:57.707227339Z", updated_at: "2021-10-04T06:37:57.707227339Z"}) {
numUids
}
}
Graphql Query
query MyQuery {
queryProduct {
name
}
}
response of the graphql query:
{
"data": {
"queryProduct": [
{
"name": "product 1"
}
]
},
"extensions": {
"touched_uids": 2,
"tracing": {
"version": 1,
"startTime": "2021-10-04T06:42:01.064395081Z",
"endTime": "2021-10-04T06:42:01.065675778Z",
"duration": 1280687,
"execution": {
"resolvers": [
{
"path": [
"queryProduct"
],
"parentType": "Query",
"fieldName": "queryProduct",
"returnType": "[Product]",
"startOffset": 110469,
"duration": 1164739,
"dgraph": [
{
"label": "query",
"startOffset": 149859,
"duration": 1123999
}
]
}
]
}
}
}
}
Then I did a mutation using dgo: https://github.com/dgraph-io/dgo#running-a-mutation and the data are shown fine using the ratel tool.
When I try again the Graphql Query:
query MyQuery {
queryProduct {
name
}
}
none of these are returned in the graphql response.
The issue is because the dgraph also wants a DType to be passed via dql mutation like so:
models.Product{
Name: "product name",
Slug: "product-slug",
Image: "test.jpg",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DType: []string{"Product"}, // here is the trick
}

why region_code not storing properly?

I am using Magento GraphQL api in my project. To create a customer address I used createCustomerAddress mutation(createCustomerAddress).
Below is the mutation that I have called to create the customer address :
mutation createAddress {
createCustomerAddress(
input: {
firstname: "test"
lastname: "name"
company: "networld"
telephone: "1231231231"
street: ["test address line 1", "test address line 2"]
city: "Rajkot"
region: { region:"Gujarat", region_code: "GJ" }
postcode: "360001"
country_code: IN
}
) {
id
prefix
firstname
lastname
middlename
city
company
country_code
default_billing
default_shipping
postcode
region {
region
region_code
}
street
suffix
telephone
vat_id
}
}
This is working properly and returning me the result as below :
{
"data": {
"createCustomerAddress": {
"id": 44,
"prefix": null,
"firstname": "test",
"lastname": "name",
"middlename": null,
"city": "Rajkot",
"company": "networld",
"country_code": "IN",
"default_billing": false,
"default_shipping": false,
"postcode": "360001",
"region": {
"region": "Gujarat",
"region_code": "GJ"
},
"street": [
"test address line 1",
"test address line 2"
],
"suffix": null,
"telephone": "1231231231",
"vat_id": null
}
}
}
But, now when I query to get the customer address, it returning wrong region_code.
Here is the query I written to get the customer address :
query{
customer{
addresses{
id
firstname
lastname
street
city
region{
region
region_code
}
country_code
postcode
telephone
}
}
}
Result :
{
"data": {
"customer": {
"addresses": [
{
"id": 44,
"firstname": "test",
"lastname": "name",
"street": [
"test address line 1",
"test address line 2"
],
"city": "Rajkot",
"region": {
"region": "Gujarat",
"region_code": "Gujarat"
},
"country_code": "IN",
"postcode": "360001",
"telephone": "1231231231"
}
]
}
}
}
As you can see, region_code in this query result and region_code in mutation result was different. Query not returning region_code that generated from the mutation. Mutation generated region_code was GJ and query returned region_code was Gujarat.
Can anyone help me why this is happening ? How to solve it ?
I just stumbled upon this bug myself in Magento 2.3.4 and it looks like it's buggy with the region_code. There's a workaround for this, try to send the region_id instead of region_code, like this:
mutation {
createCustomerAddress(input: {
region: {
region: "VendeƩ"
region_id: 799
}
country_code: FR
street: ["123 Main Street"]
telephone: "7777777777"
postcode: "77777"
city: "Phoenix"
firstname: "Bob"
lastname: "Loblaw"
default_shipping: true
default_billing: false
}) {
id
region {
region
region_code
}
country_code
street
telephone
postcode
city
default_shipping
default_billing
}
}
After this, if you retrieve the region_code, it will show fine. It looks like it has problems identifying the region by the region_code.

Mutation arguments as object

I'm using the Go implemenatation of GraphQL.
How would you configure a mutation so that it can receive arguments with more than 1 level?
For exemple, here is the list of arguments I would like to pass to a mutation CreateUser:
mutation createUser($user: CreateUser!) {
createUser(input: $user)
}
{
"user": {
"name": {
"first": "John",
"last": "Doe"
},
"email": "john#doe.com"
}
}
(Notice that I dont want to use firstname and lastname but a name object instead)
And this is my (unsuccessful) attempt so far:
var CreateUserInput = graphql.FieldConfigArgument{
"input": &graphql.ArgumentConfig{
Description: "Input for creating a new user",
Type: graphql.NewNonNull(graphql.NewInputObject(graphql.InputObjectConfig{
Name: "CreateUser",
Fields: graphql.InputObjectConfigFieldMap{
"name": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.NewInputObject(graphql.InputObjectConfig{
Fields: graphql.InputObjectConfigFieldMap{
"first": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
"last": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
})),
},
"email": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
})),
},
}
Apparently the subfields first and last are not recognized as this is what I get when I run this mutation:
{
"data": null,
"errors": [
{
"message": "Variable \"$user\" got invalid value {\"email\":\"john#doe.com\",\"name\":{\"first\":\"john\",\"last\":\"doe\"}}.\nIn field \"name\": In field \"first\": Unknown field.\nIn field \"name\": In field \"last\": Unknown field.",
"locations": [
{
"line": 1,
"column": 21
}
]
}
]
}
Is this even possible?
EDIT: See comments in the accepted answer for the solution.
This are my first ever lines of Go but I will try to convey what I think the problem is.
First lets talk about the structure you want to be going for. I will use SDL here:
type Mutation {
createUser(user: CreateUser!): Boolean! # Maybe return user type here?
}
input CreateUser {
name: CreateUserName!
email: String!
}
input CreateUserName {
first: String!
last: String!
}
Okay now that we know that we need two input types lets get started!
var CreateUserName = graphql.NewInputObject(graphql.InputObjectConfig{
Name: "CreateUserName",
Fields: graphql.InputObjectConfigFieldMap{
"first": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
"last": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
})
var CreateUser = graphql.NewInputObject(graphql.InputObjectConfig{
Name: "CreateUser",
Fields: graphql.InputObjectConfigFieldMap{
"name": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(CreateUserName),
},
"email": &graphql.InputObjectFieldConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
})
Now all that should be left is adding the mutation field to your mutation object type.

How to make a join using GraphQL?

I have a node.js app that serves sqlite database data using sequelize via graphql.
The data types are following:
Student
id: ID!
name: String!
class: Class
Class
id: ID!
title: String!
floor: Int!
I want to get an array of classes with each class containing an array of corresponding students like
[
{
"id": 1,
"title" : "first",
"students" : [
{ "id": 1, "name": "John Doe" },
{ "id": 2, "name": "Mary Smith" }
]
]
Is there any way to do it despite of that kind of reverse linking?
If your database isn't large enough yet, you could always run a one-time script to link it the other way as well, with:
Class {
id: ID!
title: String!
floor: Int!
students: [Student]!
}
Otherwise, you would have to do a manual query for all students that are taking a certain class and join that data into your query for classes.

kendo ui data grid - firebase

I'm using kendo ui data grid with a firebase (rest json response). The structure can contain multiple objects. However, these objects are not in a standard array format. See my json file below:
{
"users": {
"contactdetails": {
"email": "johnlittle#email.com"
},
"firstname": "John",
"id": 1,
"surname": "Little"
}
}
I am able to read firstname and surname onto the grids column but cannot get to the email object.
This is my schema definition:
schema: {
model: {
fields: {
id: {type: "number"},
firstname: {type: "string"},
surname: {type: "string"},
email: {type: "string"}
}
}
}
As far I know, u can not specify nested object to schema model definition. One way is you can use column template for email column.
columns: [
{ field: "firstname", title: "FirstName" },
{ field: "surname", title: "Surename" },
{ title: "Email", template: "#= data.contactdetails.email #" },
],

Resources