SurrealDB equivalent of SELECT DISTINCT - distinct

I have a table of courses that are RELATEd by requires_prerequisite to other courses. I am trying to get 2nd-level prerequisite dependencies for a course (courses that have courses as prerequisites which have this course as a prerequisite), and I have a query as follows:
SELECT id, <-requires_prerequisite<-course<-requires_prerequisite<-course AS indirect_postrequisites
FROM course WHERE id = course:APS105;
And that gives me this:
[
{
"time": "526.8µs",
"status": "OK",
"result": [
{
"id": "course:APS105",
"indirect_postrequisites": [
"course:ECE345",
"course:ECE297",
"course:ECE344",
"course:ECE295",
"course:ECE345",
"course:ECE297",
"course:ECE344",
"course:ECE295"
]
}
]
}
]
However as you will notice, there are duplicate entries in here.¹ How do I filter out the duplicates? In standard SQL I would use
SELECT DISTINCT `in` FROM requires_prerequisite
WHERE `out` IN (SELECT `in` FROM requires_prerequisite WHERE `out`='APS105';
But if I try to use
SELECT DISTINCT id, <-requires_prerequisite<-course<-requires_prerequisite<-course AS indirect_postrequisites
FROM course WHERE id = course:APS105;
then I get
{
"code": 400,
"details": "Request problems detected",
"description": "There is a problem with your request. Refer to the documentation for further information.",
"information": "There was a problem with the database: Parse error on line 1 at character 0 when parsing 'SELECT DISTINCT id, <-requires_prerequisite<-course<-requires_prerequisite<-course AS indirect_postr'"
}
How can I filter out duplicate values?
¹ If you want to know why the duplicates appear, it's because
RELATE course:ECE297->requires_prerequisite->course:APS105;
RELATE course:ECE297->requires_prerequisite->course:ECE244;
RELATE course:ECE244->requires_prerequisite->course:APS105;

After scrounging the documentation, I found the array::distinct() function which did exactly what I wanted:
SELECT id, array::distinct(<-requires_prerequisite<-course<-requires_prerequisite<-course) AS indirect_postrequisites FROM course WHERE id = course:APS105;
[
{
"time": "537.8µs",
"status": "OK",
"result": [
{
"id": "course:APS105",
"indirect_postrequisites": [
"course:ECE345",
"course:ECE297",
"course:ECE344",
"course:ECE295"
]
}
]
}
]

Related

Apollo Server federation resolvers: how to gracefully handle entity not found?

When using GraphQL federated resolvers to resolve an array, and one of the resolved items cannot be found:
Observed behaviour: null data returned for entire query, no error message.
Desired behaviour: the item which cannot be resolved is silently dropped from results array.
What works
Using Apollo Server federation, we are successfully able to resolve the following query:
query {
products {
name
reviews {
id
score
}
}
}
where products comes from the Product subgraph and score is resolved by the Review subgraph.
This works fine when all the review ids passed to the Review subgraph are resolvable.
Our Problem
Sometimes the Review subgraph deems that a review should not be returned. The business case could be, for example, it was automatically marked as spam and is blocked until a manual check is done.
In this situation, the Review subgraph returns null for this ID. Example query:
query {
_entities(representations: [
{id: 1, __typename: "Review"},
{id: 2, __typename: "Review"}
]) {
...on Review {
id
score
}
}
}
Result
{
"data": {
"_entities": [
{
"id": "1",
"score": "94"
},
null
]
}
}
When this happens, we would want the federated results to contain the Product and only review 1, the non-resolveable review id 2 having been dropped from the array. Like this:
{
"data": {
"products": {
"name": "Phone cover",
"reviews": [
{
"id": "1",
"score": "94"
}
]
}
}
}
However, Apollo Server returns null for the entire query, with no error message:
{
"data": null
}
Is this expected behaviour? Is there any way to gain the result I want, or otherwise control how Apollo reacts when one item in a reference array is not resolved?

How to use the "nextToken" parameter to test Pagination?

I am working with a sample of graphql query which I want to further bind to a FlatList object in a React-Native app. But I am still struggling to understand what I should pass on then nextToken parameter in order to get a slice of objects destined to a second page...
Tried to pass the next or last id or index, but it didn't work - it asks me to provide a valid nextToken, which I don't know what kind of data it is.
I'm running through AppSynch console.
My query:
query ListResources(
$nextTokenPlants: String = "Orange Tree"
$limitPlants: Int = 3
) {
listResources {
items {
id
name
Plants(limit: $limitPlants, nextToken:$nextTokenPlants) {
items {
id
name
filterName
description
bath
tea
insence
children
}
nextToken
}
}
nextToken
}
}
This is the result I get:
{
"data": {
"listResources": {
"items": [
{
"id": "361dee16-d567-41ed-b1d4-9baa4a7ffdcc",
"name": "Plantas",
"Plants": null
}
],
"nextToken": null
}
},
"errors": [
{
"path": [
"listResources",
"items",
0,
"Plants"
],
"data": null,
"errorType": "DynamoDB:UserIllegalArgumentException",
"errorInfo": null,
"locations": [
{
"line": 9,
"column": 7,
"sourceName": null
}
],
"message": "com.amazonaws.deepdish.common.pagination.InvalidPaginationTokenException: Invalid pagination token given."
}
]
}
I expected to get a list of 3 of the itens stored on "Plants", starting from the "Orange Tree" onwards... Could anyone pls shed some light on it?
nextToken is a String that you get in the response when you send a request, looks like
eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGdtYVZObHlaR3FSa3hDRnFVWWdFeEZDM0FMY1JRdE9UOEt2dWFLMExzcjJ3RlBPMGdpcC96bjQ5VjFOVElKUng1M0FBQUNlVENDQW5VR0NTcUdTSWIzRFFFSEJxQ0NBbVl3Z2dKaUFnRUFNSUlDV3dZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF4VEt5Myt3RUJuSzVSU2hsUUNBUkNBZ2dJc1lmdDk2WVVmQ053Tms2WGkxc3Z2bUgzSGFQZTdNTm1DQWhDcWJ5RFlydXZwTmR6WUNBQ0pJS1RZQlVWdk1xbU9EV2s2SVdLTzlqNmRhenNWZGZYTmFTQmxseE9yUS9BZWY0c2NpL1duWVUweWEyNCthZGQxcVNaMGZEWDZUdkJDak1XQjQ4QmhTQmxLejk2TFpiZ3pDN3dJTzVPRStFbUxHdVhRcURXcUpNZDM3Rm0yNUdiQVU1Tlg1YWVtWE1PbnVKSkZpTzA3U3ZhdUVZMWZwaXZCVU9pMHlxTVlIYk5PMkQ4aDZRVmQ4eW4yTXl3YU9UUHYwWFJZNitrakgvNGlyOWtrdlVXK1pvNFdOeDFBL2h1MlF4Z0lSczQ3d0xTT2NsaXk1Y3o0eFFzM2xqREhYL3M0TTVwT2phTCt0TGpYOUlWcGZCVW45bUgwWEw4ZEFkR0VZRGdjeWpMUHlPdWFnREVNMWR4M09neTg4NGJPclJ3VVgrRmM0UHpGekRqSHZjcjBGSVVXNEM2ZUxzYVRtRjNFakhLRk9ERllDWWkrQ01QNFg0a0dCdTFJQ3BLQjNJdEx2VTZHcUxNVDRMd3NJbkk4SVBhZm1MRnYxRTZDbWxxMnFKZ2wxY1BEVmR6MVFDc0Ezby9vR0VHUkI2VkJtc3VFSUFuOW10OVJzaWpyaklqUm5DQzlSWHA3NnA0WlhWanBJY0dSVU9GTktvZGNnMVpNbGV0a200clhBUGJacFZ5TDdkcnQyTXlEVERQd1crcjZsRHJUUVJJZzI4MEl3Y3ZkQzB1RWRrb0hqTlZPR0kwSWxsSnZ5RjRWTCtNNzRuWXcwNVNSWllJODdGcGdzR21LZjRvWVA1VG9temRVUUR0YWkrZVRJcUxGRjlGYzk0UUNwZlYrVlpmeVU0Mk4yTnRtNi9MYUhrZ08zdGRTUHN1bGhQWVRuMGRQNU5aWG5pODU1eGZyL1N2dDQ2VU0xb3I2UEE9PSJ9
and it has nothing to do with your table keys.
Let me explain now how does it work:
When you send the request for the first time, you don't send nextToken since you don't have it and then you get the first portion of your data.
When you receive that first portion, if there exist more data, you get nextToken in the response.
Now, you have nextToken, you send another request to get the 2nd portion of your data. You should send that token in the request, so your backend knows from where to start.
You get your 2nd portion of data and a new nextToken if there is still some data to fetch (then you need to repeat step 2) or null in nextToken if there is no more data.
I hope that it's clear now

How to fuse rows in Pentaho Kettle

So, I'm moving an Oracle DB to a Mongo DB. I have a collection called Work, where all films, painting and the rest are stocked. I also have a collection called Authority, where all people that ever interacted with one work are (actors, painter, etc.) I'm trying to make a link between Authorities and Works inside the Work collection this way:
"workCS": {
"casting": [
{
"authority": ObjectID("anID"),
"role": [
"actor",
"realisator"
]
}
],
[
{
"authority": ObjectID("otherID"),
"role": [
"actor"
]
}
]
}
So, I know how to make a manyToMany joint in Pentaho Kettle, so I had no problem making the basic structure of the collection. However, I can't find a way to make the role table inside the casting table, and end up with something like this:
"workCS": {
"casting": [
{
"authority": ObjectID("anID"),
"role": [
"actor"
]
}
],
[
{
"authority": ObjectID("anID"),
"role": [
"realisator"
]
}
],
[
{
"authority": ObjectID("otherID"),
"role": [
"actor"
]
}
]
}
Which is incoherent with the post treatment we do to our data.
When I make my SQL to get the data from the Oracle DB, I have something like this:
"id"; "LastName"; "FirstName"; "Role";
1; "Radcliffe"; "Daniel"; "Actor";
1; "Radcliffe"; "Daniel"; "Writer";
2; "Grint"; "Rupert"; "Actor";
Is there a way to fuse rows in Pentaho, so this example is displayed this way?
"id"; "LastName"; "FirstName"; "Roles";
1; "Radcliffe"; "Daniel"; "Actor, Writer";
2; "Grint"; "Rupert"; "Actor";
The step you are looking for is the Group by, with and Aggregation type of Concatenate strings separated by , on the roles.
You need to specify the other three columns as keys in the Group field, because even though the only real key is the Authority_id, if you do not specify them as group field, they will disappear.
Also use the Memory Group by,unless you have really, really a lot of rows, in which case use the Group by and make sure the data is sorted by Authority_id (they will automatically also sorted by Names).

Which is the better design for this API response

I'm trying to decide upon the best format of response for my API. I need to return a reports response which provides information on the report itself and the fields contained on it. Fields can be of differing types, so there can be: SelectList; TextArea; Location etc..
They each use different properties, so "SelectList" might use "Value" to store its string value and "Location" might use "ChildItems" to hold "Longitude" "Latitude" etc.
Here's what I mean:
"ReportList": [
{
"Fields": [
{
"Id": {},
"Label": "",
"Value": "",
"FieldType": "",
"FieldBankFieldId": {},
"ChildItems": [
{
"Item": "",
"Value": ""
}
]
}
]
}
The problem with this is I'm expecting the users to know when a value is supposed to be null. So I'm expecting a person looking to extract the value from "Location" to extract it from "ChildItems" and not "Value". The benefit to this however, is it's much easier to query for things than the alternative which is the following:
"ReportList": [
{
"Fields": [
{
"SelectList": [
{
"Id": {},
"Label": "",
"Value": "",
}
]
"Location": [
{
"Id": {},
"Label": "",
"Latitude": "",
"Longitude": "",
"etc": "",
}
]
}
]
}
So this one is a reports list that contains a list of fields which on it contains a list of fieldtype for every fieldtype I have (15 or something like that). This is opposed to just having a list of reports which has a list of fields with a "fieldtype" enum which I think is fairly easy to manipulate.
So the Question: Which format is best for a response? Any alternatives and comments appreciated.
EDIT:
To query all fields by fieldtype in a report and get values with the first way it would go something like this:
foreach(field in fields)
{
switch(field.fieldType){
case FieldType.Location :
var locationValue = field.childitems;
break;
case FieldType.SelectList:
var valueselectlist = field.Value;
break;
}
The second one would be like:
foreach(field in fields)
{
foreach(location in field.Locations)
{
var latitude = location.Latitude;
}
foreach(selectList in field.SelectLists)
{
var value= selectList.Value;
}
}
I think the right answer is the first one. With the switch statement. It makes it easier to query on for things like: Get me the value of the field with the id of this guid. It just means putting it through a big switch statement.
I went with the first one because It's easier to query for the most common use case. I'll expect the client code to put it into their own schema if they want to change it.

Non unique query with Freebase MQL read google api

It seems I am only able to do unique queries (i.e. including an entity id in the query) with the new freebase MQL read api:
The following searches on id and type:
https://www.googleapis.com/freebase/v1/mqlread?query={"name":null,"id":"/en/bob_dylan","type":"/people/person"}
and successfully returns:
{
"result": {
"type": "/people/person",
"id": "/en/bob_dylan",
"name": "Bob Dylan"
}
}
The following searches with type only:
https://www.googleapis.com/freebase/v1/mqlread?query={"name":null,"type":"/people/person"}
or
https://www.googleapis.com/freebase/v1/mqlread?query={"name":[],"type":"/people/person"}
and returns the following error:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "badRequest",
"message": "Unique query may have at most one result. Got 100"
}
],
"code": 400,
"message": "Unique query may have at most one result. Got 100"
}
}
I expected it to return a list of people's names
You have to wrap your query in [ ], as in the following example:
https://www.googleapis.com/freebase/v1/mqlread?query=[{"name":[],"type":"/people/person"}]
I too faced a similar problem recently. The best way to make sure you get a single result set is to use "limit:1" parameter in your mql query.
for example:
https://www.googleapis.com/freebase/v1/mqlread?query={"type":[],"name":"india","limit":1}

Resources