First a little background; The GAE app was developed by a third party and provides an interface for some embedded hardware to save data to the cloud over a mobile network. The data is POSTed from the device as a JSON object over HTTP. The app on GAE is written in python, and I have full access to the source code (even though I don't fully understand it!)
The data field "points" is a fixed length array of items with a location, datestamp and two numbers.
The data model for a single point is thus (obfuscated for security):
class MeasurementPoint(EndpointsModel):
Val1 = ndb.FloatProperty()
Val2 = ndb.FloatProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
loc = ndb.GeoPtProperty()
and for the encapuslating class (again obfuscated):
class CompletedReading(EndpointsModel):
_message_fields_schema = ('id', 'inspection_id', 'timestamp',
'points',
'Val1_average', 'Val2_average', 'Val1_min',
'location_id',
'organisation_id', )
timestamp = ndb.DateTimeProperty(auto_now_add=True)
points = ndb.LocalStructuredProperty(Measurement, repeated=True, compressed=True)
Val1_average = ndb.FloatProperty()
Val2_average = ndb.FloatProperty()
Val1_min = ndb.FloatProperty()
... hopefully you get the idea.
The posted JSON is something like:
{
"points": [
{
"Val1": 999,
"Val2": 319160.3,
"timestamp": "2020-03-03T15:56:01.000000",
"location": {
"lat": 52.75024,
"lon": -1.919412
}
},
{
"Val1": 999,
"Val2": 319160.3,
"timestamp": "2020-03-03T15:56:02.000000",
"location": {
"lat": 52.75024,
"lon": -1.919412
}
},
..... n sets of "points" ( always a fixed size array )
],
"organisation_id": "5634161670881280",
"location_id": "5638358357245952",
"timestamp": "2020-03-03T15:55:58.000000"
}
So... I now have this data stored in the database and I am writing a .net app (in VB, but it could easily be C#) and I am using the Google.Cloud.Datastore.V1 API to access it. So far this is all working and I can list the CompletedReading entity using the following simple code:
Imports Google.Cloud.Datastore.V1
Imports Google.Protobuf
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ProjectId As String = "xxxxxxxxxx" ' Obfuscated for security
Dim db As DatastoreDb
Dim kind As String = "CopmletedReading"
Dim q As Query
Dim Entry As Entity
' In order for this to work you have to set the environment variable
' GOOGLE_APPLICATION_CREDENTIALS= <Path to zzzzzzzzzzzz.json> (Obfuscated for security)
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "zzzzzzzzzzzz.json")
db = DatastoreDb.Create(ProjectId)
q = New Query(kind)
Label1.Text = ""
For Each Entry In db.RunQueryLazily(q)
Label1.Text = Label1.Text & vbCrLf & vbCrLf & vbCrLf & vbCrLf &
"ToString:" & vbCrLf & Entry.ToString & vbCrLf & vbCrLf &
"Key:" & vbCrLf & Entry.Key.ToString & vbCrLf & vbCrLf &
"Properties:" & vbCrLf & Entry.Properties().ToString & vbCrLf & vbCrLf &
"name:" & vbCrLf & Entry.Item("points").ToString
Next
End Sub
End Class
results in the following output for each entity ....
ToString:
{ "key": { "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": "CompletedReading", "id": "6320665133056000" } ] }, "properties": { "Val1_average": { "doubleValue": 422 }, "Val2_average": { "doubleValue": 278 }, "organisation_ref": { "keyValue": { "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": "Organisation", "id": "5629499534213120" } ] } }, "location_id": { "keyValue": { "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": location", "id": "4922041111150592" } ] } }, "points": { "arrayValue": { "values": [ { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQ8VDkUqHJxSHDn5yYklmfl5QCkRbcPVjjNu713g5WB5d9oJ1vQHEgd0iqQ42KU4SzJzU4sLEnMLQCZwLNu+ZcuOzxeYiqSleMpSi0oyk9GNX1DoAAD8CChx", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgYIqhyIVDk4pjpz85MSSzPw8oJSItuFqxxm39y7wcrB8HMzQk/5A4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxDwocAK8uJ8g=", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQPVDkUqHJxSHDn5yYklmfl5QCkRbcM3Bmp/9y7wcrB8KWAhlPFA4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxCwodAKVhJzw=", "excludeFromIndexes": true } ] } }, "timestamp": { "timestampValue": "2016-12-14T10:08:47Z" }, "Val1_min": { "doubleValue": 399 } } }
Key:
{ "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": "CompletedReading", "id": "6320665133056000" } ] }
Properties:
{ "Val1_average": { "doubleValue": 422 }, "Val2_average": { "doubleValue": 278 }, "organisation_ref": { "keyValue": { "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": "Organisation", "id": "5629499534213120" } ] } }, "location_id": { "keyValue": { "partitionId": { "projectId": "xxxxxxxxxx" }, "path": [ { "kind": "location", "id": "4922041111150592" } ] } }, "points": { "arrayValue": { "values": [ { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQ8VDkUqHJxSHDn5yYklmfl5QCkRbcPVjjNu713g5WB5d9oJ1vQHEgd0iqQ42KU4SzJzU4sLEnMLQCZwLNu+ZcuOzxeYiqSleMpSi0oyk9GNX1DoAAD8CChx", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgYIqhyIVDk4pjpz85MSSzPw8oJSItuFqxxm39y7wcrB8HMzQk/5A4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxDwocAK8uJ8g=", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQPVDkUqHJxSHDn5yYklmfl5QCkRbcM3Bmp/9y7wcrB8KWAhlPFA4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxCwodAKVhJzw=", "excludeFromIndexes": true } ] } }, "timestamp": { "timestampValue": "2016-12-14T10:08:47Z" }, "Val1_min": { "doubleValue": 399 } }
name:
{ "arrayValue": { "values": [ { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQ8VDkUqHJxSHDn5yYklmfl5QCkRbcPVjjNu713g5WB5d9oJ1vQHEgd0iqQ42KU4SzJzU4sLEnMLQCZwLNu+ZcuOzxeYiqSleMpSi0oyk9GNX1DoAAD8CChx", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgYIqhyIVDk4pjpz85MSSzPw8oJSItuFqxxm39y7wcrB8HMzQk/5A4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxDwocAK8uJ8g=", "excludeFromIndexes": true }, { "meaning": 22, "blobValue": "eJwrkpXiy8gvyqzKzytJzInPKa1QYNDiVGQAgQPVDkUqHJxSHDn5yYklmfl5QCkRbcM3Bmp/9y7wcrB8KWAhlPFA4oBOkRQHuxRnSWZuanFBYm4ByASOXdu3bNnx+QJTkbQUT1lqUUlmMrrxCwodAKVhJzw=", "excludeFromIndexes": true } ] } }
This is the point at which I'm stuck. I'm not familiar with GAE/Datastore/Python or the Google API .... I have tried unsuccesfully to try to deserialise the blob into a VB class. I can't find any references in the API to a LocalStructuredProperty so I can't deal with it directly.
My "last ditch" thought was to attempt to write some python on the web server to read the datastore back into a suitable object then fire the data back at my VB app as JSON, but I'd really prefer to be able to access the object in the datastore from VB and to get my array of points back.
Can anyone suggest where I go from here?? Thanks for looking.