Google Cloud Datastore REST API v1 (gqlQuery) - database

Would someone walk me through the syntax on how to use the runQuery method to preform a gqlQuery using the Google Cloud Datastore REST API v1. I only need help in understanding the query structure of the REST API and do not need help with Google OAUTH or setting up Cloud Datatore. I have included a link to the documentation, example gqlQuery to run and Cloud Datastore structure below.
Method: projects.runQuery
https://cloud.google.com/datastore/docs/reference/rest/v1/projects/runQuery
Example gqlQuery = ("Select * From Customer")
Sample Google DataStore Structure
id = "78090499534213120"
Address = "888 Fake St"
City = "Fake City"
FirstName = "Name"
LastName = "Name"
State = "CT"

POST https://datastore.googleapis.com/v1/projects/{YOUR_PROJECT_ID}:runQuery?key={YOUR_API_KEY}
Where {YOUR_PROJECT_ID} can be found on the Cloud Console home page for your project and is alphanumeric.
The body of the message will be a JSON string with the details of the query, so in your case:
{
"gqlQuery":{"queryString": "select * from customer"}
}
If you want to include conditionals, you can do this as well by using parameter binding. The below example shows how to use positional binding to achieve this:
{
"gqlQuery":
{
"queryString": "select * from Customers where State = #1 AND FirstName = #2",
"positionalBindings": [
{"value": {"stringValue": "CT"}}.
{"value": {"stringValue": "Name"}}
]
}
}
Instead of positional binding, you could also do named bindings:
{
"gqlQuery":
{
"queryString": "select * from Customers where State = #State AND FirstName = #FirstName",
"namedBindings": {
"State": {"value": {"stringValue": "CT"}},
"FirstName": {"value": {"stringValue": "Name"}}
}
}
}
Lastly, and not recommended as it can lead to query injection attacks, you can include literals in the query string itself by setting the appropriate flag:
{
"gqlQuery":
{
"queryString": "select * from Customers where State = 'CT' AND FirstName = 'Name'",
"allowLiterals": true
}
}

Do you get a proper response back when you make this request? I get the following 200 response, but don't see any of my expected rows of data
{
"batch": {
"entityResultType": "PROJECTION",
"endCursor": "CgA=",
"moreResults": "NO_MORE_RESULTS"
}
}

Related

Performing two firebase queries to inner join 2 lists

I'm building a simple marketplace web app where the user posts their products. I want to get the user owner of each product. Please tell me how do I perform Firebase inner joins using observables!
productsRef: AngularFireList<any>;
///
constructor(
private db: AngularFireDatabase,
private userService: UserService
) {
this.productsRef = db.list('/products');
}
getProductsList() {
const product$ = this.productsRef.valueChanges();
// 1st observable to get the products
const productsResults$ = product$.pipe(
switchMap(products => products)
)
);
productsResults$.subscribe(
console.log,
console.error,
() => console.log('completed httpResult$')
);
// 2nd observable to get the user
const user$ = this.userService.getUserById(Id);
productsResults$.subscribe(
console.log,
console.error,
() => console.log('completed httpResult$')
);
}
i get the 2 following results.
Products
[
{
"key": "-TM2Y6vBk70rgKZ3zTUAw",
"name": "T-shirt",
"size": "M",
"user": "-NDNPe47CDTbjmwGgW_3",
},
]
User
{
"key": "-NDNPe47CDTbjmwGgW_3",
"username": "Alex199",
},
the end result i want
{
"key": "-TM2Y6vBk70rgKZ3zTUAw",
"name": "T-shirt",
"size": "M",
"user": {
"key": "-NDNPe47CDTbjmwGgW_3",
"username": "Alex199",
},
},
How can I achieve this using observable?
There is no Inner Join clause in NoSQL databases. So if you want to read some data at a location based on what you read at another location, then you have to perform two separate requests. There is no way you can get that data in a single go.
Alternatively, if you don't want to perform two separate queries, then you can save user data right inside the product node, or vice versa. This practice is called denormalization and is a common practice when it comes to NoSQL databases like Realtime Database. For a better understanding, I recommend you see this video.
If you consider at some point in time try using Cloud Firestore, then I recommend you read my answer from the following post:
What is denormalization in Firebase Cloud Firestore?

How to store a complex json response from api in local database in flutter?

I want to save the whole json response from api. I tried SQFLITE library to store but i cant able to achieve to store a complete json as it need to store in a table format. I'm very new to flutter. can any body suggest how can i achieve this. Below i'm attaching my sample json for your reference.
{
"result": {
"allitems": {
"answered_status": 0,
"list_items": [
{
"is_answered": false,
"options": [
{
"image_url": "assets/images/orders/jersey.jpg",
"description": "Jersey",
"title": "Jersey",
"price": 23
},
{
"image_url": "assets/images/orders/bat.png",
"description": "Bat",
"title": "Bat",
"price": 5
},
]
}
],
"no_of_items": 12,
"title": "ALL"
}
},
"status_code": 200
}
I was wrong about SharedPreferences in my comment. Turns out SharedPreferences doesn't support Map<dynamic, dynamic> and only up to List<String> yet.
So you can use a database management package sembast made by the same guy who made SQFLite.
You can get help with this link to convert JSON objects to Map and vice-versa.
EDIT -
You can do something like -
import 'package:sembast/sembast.dart';
Map<dynamic, dynamic> sampleMap;
// Skipping this part
sampleMap = // Retrive and convert JSON to Map
// A sample DB in the current directory
String dbPath = 'sample.db';
DatabaseFactory dbFactory = databaseFactoryIo;
// We use the database factory to open the database
Database db = await dbFactory.openDatabase(dbPath);
var store = intMapStoreFactory.store();
// Storing Map to DB
var key = await store.add(db, sampleMap);
// Retrieving values back
var record = await store.record(key).getSnapshot(db);
// From your provided sample JSON in question
var value = record["result"]["allitems"]["list_items"][0]["options"]["image_url"];
print(value);
// value = 'assets/images/orders/jersey.jpg'
Similarly, you can explore the documentation of the package for more data operations.
Convert it to a string, you can store it in shared preference.
import 'dart:convert';
...
var s = json.encode(myMap);
// or var s = jsonEncode(myMap);
json.decode()/jsonDecode() makes a map from a string when you load it.

How can we set context variables for IBM Watson from backend

I want to pass some values to frontend in form of context variables in IBM Watson through my Node app. How can I achieve it?
I tried to add the value I want to add to current context variable object and sent that back. Still no help. Is there any way I can do it?
Edit:
Right now, I am adding the required value as a new key-value pair to the context object from Node app as follows.
...
let user_name = "MJ"
context.user_name = user_name
response.send({
output: output,
context: JSON.stringfy(context)
})
...
And in Watson Console, in one of the dialogue nodes I have used like,
Hey $user_name, How are you?
But the output I am getting is,
Hey , How are you?
I can see user_name value in the context object, but I can't use it in the way I mentioned above. Is there any other way to do so?
Any help is appreciated. Thanks in advance!
I was having the same problem. My solution was changing the code when you call the IBM server and request .json:
...
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text,
context: {username : variable},
...
The username I set in Watson Assistant as well as a context, the variable I used a function to get the name though Query (Because in my application, I am calling the chatbot though an IFrame.), but you can use any variable set on javascript.
You can add any value to the Context object, which can be accessed in your Node.JS app and if you send that value to the front-end, then it should be accessible in the UI as well.
Below I've mentioned a sample welcome response from Conversation service. You can access the Context object from the response of Conversation service and add a new key-value pair to that object. In the response, you'll see that I'm accessing a context variable username that has the value MJ, which has been added dynamically to the context.
`
{
"intents": [],
"entities": [],
"input": {
"text": ""
},
"output": {
"text": ["Hello MJ! How can I help you today?"],
"nodes_visited": ["Conversation Start"],
"log_messages": []
},
"context": {
"username": "MJ",
"conversation_id": "5835fa3b-6a1c-4ec5-92f9-22844684670e",
"system": {
"dialog_stack": [{
"dialog_node": "Conversation Start"
}],
"dialog_turn_counter": 1,
"dialog_request_counter": 1,
"_node_output_map": {
"Conversation Start": [0]
}
}
}
`
Now to update the context, fetch the response and add a new key-value pair
`
var convResponse = <responseObj from Conversation call>;
var context = convResponse.context;
//add new value to context
context["new_key"] = "new value";
`
Now the next call that you make to Conversation, use this updated context instead of the context you received from the previous call. You can send back the response from Conversation to the front-end as well which can then be shown to the user.
var payload = {
assistantId: assistantId,
sessionId: req.body.session_id,
context: {
skills: {
"main skill": {
user_defined: {
username: 'John Doe'
}
}
}
},
input: {
message_type: 'text',
text: "blah",
},
};
works for me. Seen here: https://medium.com/#pranavbhatia_26901/watson-assistant-v2-context-sharing-3ca18626ed0d

getconfig() for Community Connectors, how to employ user input

The Community Connector feature is very new, and I have searched, there isn't much information. We are building a Community Connector to enable Data Studio to pull API data from Google My Business Insights.
the getconfig() function is described here: https://developers.google.com/datastudio/connector/reference#getconfig
We can display our configuration options to the user, that was easy, but the API reference is unclear what the next step is: how to pass the user input to the next step. Pardon me if I am not using the proper terms here.
var config = {
configParams: [
{
"type": "SELECT_SINGLE",
"name": "SELECT_SINGLE",
"displayName": "Select a Location",
"helpText": "Pick One!",
"options": [
{
"label": locationName,
"value": name
},
{
"label": "altLocationName",
"value": "altName"
}
]
},
]
};
return config;
}
The preceding code displays properly to the user and the user can make a selection from the pull-down in Data Studio when making an initial data connection. But to repeat the question another way: how do we access the selection that the user chose?
The getData(), getSchema(), and getConfig() functions are all called with a parameter (which is called "request" in the documentation). The parameter is an object containing various info at each stage.
At the getConfig() stage, it includes a property called languageCode, in my case set to 'en-GB'.
The getSchema() stage is provided a property called configParams, which is essentially the result of all the settings in getConfig() after the user has set them.
Finally, getData() gets the most info, including whether this request is for extracting sample data for google to run heuristics on, and most importantly: again the configParams.
Here's what a sample request object might look like:
{ //------ Present in:
languageCode: en-GB, //////-Only getConfig()
configParams: { //////-getSchema() + getData()
SELECT_SINGLE: altName ////-+
}, //
scriptParams: { //////-Only getData()
sampleExtraction: true ////-|
lastRefresh: 'new Date()' ////-+
}, //
fields: [ //////-Only getData()
{ name: FooAwesomeness }, ////-|
{ name: BarMagicality }, ////-|
{ name: BazPizzazz } ////-+
] //
dimensionsFilters: [ //////-Only getData()
[{ // |
fieldName: "string", ////-|
values: ["string", ...], ////-|
type: DimensionsFilterType, ////-|
operator: Operator ////-+
}] //
] //
} //------
Do note
that the name field in your code, currently set to SELECT_SINGLE, would be better suited to be called location because that it how you'll access it later on.
In this way you would
access:
request.configParams.location
rather than
request.configParams.SELECT_SINGLE
:)
Also note
that the format for specifying a configuration screen has been updated. Your configuration would now be able to be done as follows:
function getConfig(request) {
var cc = DataStudioApp.createCommunityConnector();
var config = cc.getConfig();
config
.newSelectSingle()
.setId('location') // You can call this "location"
.setName('Select a Location')
.setHelpText('Pick One!')
.addOption(config.newOptionBuilder()
.setLabel('Location Name')
.setValue('value'))
.addOption(config.newOptionBuilder()
.setLabel('Alternate Location Name')
.setValue('altValue'))
config.setDateRangeRequired(true);
config.setIsSteppedConfig(false);
return config.build();
}
See: Connector API Reference
See: Build a Connector Guide
The user selections will be passed to getSchema() and getData() requests under configParams object.
Using your example, let's assume the user selects altLocationName in the configuration screen. In your getSchema() and getData() functions, request.configParams.SELECT_SINGLE should return altName.

How to set up Firebase location as a Backbone Model ID?

I use BackFire - Firebase integration with Backbone.js
Examining BackFire demo application I see that Firebase location is set as "root" key and as a value for ID key.
JSON response from Firebase
{
"-It-MYaWEFBI1QGD8PXB":
{
"title":dummy title",
"id": "-It-MYaWEFBI1QGD8PXB"
}
}
In Model I see that Firebase location is set as Model ID.
Backbone Model attributes
attributes: {
id: '-IswDV_2rwZu3WHO0giQ'
title: 'dummy title'
},
id : '-IswDV_2rwZu3WHO0giQ'
I wonder how does data structure look like in Firebase Forge (backend) which creates response described above?
By going to the TODO page and typing in this command:
new Firebase('https://backbone.firebaseio.com').once('value', function(ss) {
console.log(JSON.stringify(ss.val(), null, 2))});
I am able to see the data structure looks like this:
{
"-It-MYaWEFBI1QGD8PXB": {
"id": "-It-MYaWEFBI1QGD8PXB",
"title": "prepare lunch"
},
"-It-Mch8_bA23vkwAbUZ": {
"id": "-It-Mch8_bA23vkwAbUZ",
"title": "install Linux"
}
}
So basically, because it's a demo, Anant has obeyed KISS and put the todo items at the root level. In a sophisticated application, you'd need to have more nesting and depth, of course.

Resources