How to query an array of objects in Firestore using structuredQuery of REST API? - google-cloud-firestore

I am trying to fetch data from Firestore using REST API. I am not able to write a structuredQuery to query an array of objects.
The user data is present like:
{
"tokens": [{
"token": "123345",
"expiry": "2019-08-07T05:42:48.567Z"
},
{
"token": "345667",
"expiry": "2019-08-06T05:42:48.567Z"
}
],
"userName": "Jane"
}
{
"structuredQuery": {
"select":{
"fields":[{
"fieldPath":"userName"
}]
},
"where": {
"fieldFilter": {
"field": {
"fieldPath": "tokens.token"
},
"op": "EQUAL",
"value": {
"stringValue": "123345"
}
}
},
"from": [{
"collectionId": "userData"
}]
}
The expected result would be to get userName. But the actual result is:
[{ "readTime": "2019-08-06T07:00:48.624353Z" }]
Even though the data is present in the database, I am getting the above result.

Related

Cloudant database search index

I have a Json document in cloudant as:
{
"createdAt": "2022-10-26T09:16:29.472Z",
"user_id": "4499c1c2-7507-4707-b0e4-ec83e2d2f34d",
"_id": "606a4d591031c14a8c48fcb4a9541ff0"
}
{
"createdAt": "2022-10-24T11:15:24.269Z",
"user_id": "c4bdcb54-3d0a-4b6a-a8a9-aa12e45345f3",
"_id": "fb24a15d8fb7cdf12feadac08e7c05dc"
}
{
"createdAt": "2022-10-24T11:08:24.269Z",
"user_id": "06d67681-e2c4-4ed4-b40a-5a2c5e7e6ed9",
"_id": "2d277ec3dd8c33da7642b72722aa93ed"
}
I have created a index json as:
{
"type": "json",
"partitioned": false,
"def": {
"fields": [
{
"createdAt": "asc"
},
{
"user_id": "asc"
}
]
}
}
I have created a index text as:
{
"type": "text",
"partitioned": false,
"def": {
"default_analyzer": "keyword",
"default_field": {},
"selector": {},
"fields": [
{
"_id": "string"
},
{
"createdAt": "string"
},
{
"user_id": "string"
}
],
"index_array_lengths": true
}
}
I have created a selctor cloudant query :
{
"selector": {
"$and": [
{
"createdAt": {
"$exists": true
}
},
{
"user_id": {
"$exists": true
}
}
]
},
"fields": [
"createdAt",
"user_id",
"_id"
],
"sort": [
{
"createdAt": "desc"
}
],
"limit": 10,
"skip": 0
}
This code work fine inside the cloudant ambient.
My problem is in the Search Index.
I created this function code that works,
function (doc) {
index("specialsearch", doc._id);
if(doc.createdAt){
index("createdAt", doc.createdAt, {"store":true})
}
if(doc.user_id){
index("user_id", doc.user_id, {"store":true})
}
}
result by this url:
// https://[user]-bluemix.cloudant.com/[database]/_design/attributes/_search/by_all?q=*:*&counts=["createdAt"]&limit=2
{
"total_rows": 10,
"bookmark": "xxx",
"rows": [
{
"id": "fb24a15d8fb7cdf12feadac08e7c05dc",
"order": [
1.0,
0
],
"fields": {
"createdAt": "2022-10-24T11:15:24.269Z",
"user_id": "c4bdcb54-3d0a-4b6a-a8a9-aa12e45345f3"
}
},
{
"id": "dad431735986bbf41b1fa3b1cd30cd0f",
"order": [
1.0,
0
],
"fields": {
"createdAt": "2022-10-24T11:07:02.138Z",
"user_id": "76f03307-4497-4a19-a647-8097fa288e77"
}
},
{
"id": "2d277ec3dd8c33da7642b72722aa93ed",
"order": [
1.0,
0
],
"fields": {
"createdAt": "2022-10-24T11:08:24.269Z",
"user_id": "06d67681-e2c4-4ed4-b40a-5a2c5e7e6ed9"
}
}
]
}
but it doesn't return the id sorted by date based on the createdAt and user_id keys.
What I would like is to get a list of an organized search with the index of the createdAt and user_id keys without having to indicate the value; a wildcard type search
Where am I wrong?
I have read several posts and guides but I did not understand how to do it.
Thanks for your help.
You say you want to return a list of id, createdAt and user_id, sorted by createdAt and user_id. And that you want all the documents returned.
If that is the case, what you need to do is simply create a MapReduce view of your data that emits the createdAt and user_id fields in that order, i.e. :
function (doc) {
emit([doc.createdAt, doc.user_id], 1);
}
You don't need to include the document id because that comes for free.
You can then query the view by visiting the URL:
https://<URL>/<database>/_design/<ddoc_name>/_view/<view_name>
You will get all the docs like this:
{"total_rows":3,"offset":0,"rows":[
{"id":"2d277ec3dd8c33da7642b72722aa93ed","key":["2022-10-24T11:08:24.269Z","06d67681-e2c4-4ed4-b40a-5a2c5e7e6ed9"],"value":1},
{"id":"fb24a15d8fb7cdf12feadac08e7c05dc","key":["2022-10-24T11:15:24.269Z","c4bdcb54-3d0a-4b6a-a8a9-aa12e45345f3"],"value":1},
{"id":"606a4d591031c14a8c48fcb4a9541ff0","key":["2022-10-26T09:16:29.472Z","4499c1c2-7507-4707-b0e4-ec83e2d2f34d"],"value":1}
]}

What is the reason fo this difference in Facebook messages webhook JSON scheme?

I'm reading the Facebook Send API and events docs, and I'm surprised to see some examples define the message at the top level of the JSON object hierarchy (here for "text message")
{
"sender":{
"id":"<PSID>"
},
"recipient":{
"id":"<PAGE_ID>"
},
"timestamp":1458692752478,
"message":{
"mid":"mid.1457764197618:41d102a3e1ae206a38",
"text":"hello, world!",
"quick_reply": {
"payload": "<DEVELOPER_DEFINED_PAYLOAD>"
}
}
}
While others examples have a different object structure:
{
"id": "682498302938465",
"time": 1518479195594,
"messaging": [
{
"sender": {
"id": "<PSID>"
},
"recipient": {
"id": "<PAGE_ID>"
},
"timestamp": 1518479195308,
"message": {
"mid": "mid.$cAAJdkrCd2ORnva8ErFhjGm0X_Q_c",
"attachments": [
{
"type": "<image|video|audio|file>",
"payload": {
"url": "<ATTACHMENT_URL>"
}
}
]
}
}
]
}
Here is seems like the object is the first example is instead contained in a messaging array. I can't find either what id corresponds to in this second example : there is no table detailing the fields on why the hierarchy is different here.
Finally, there is another example with a different structure:
{
"object": "page",
"entry": [
{
"id": "<PAGE_ID>",
"time": 1583173667623,
"messaging": [
{
"sender": {
"id": "<PSID>"
},
"recipient": {
"id": "<PAGE_ID>"
},
"timestamp": 1583173666767,
"message": {
"mid": "m_toDnmD...",
"text": "This is where I want to go: https:\/\/youtu.be\/bbo_fZAjIhg",
"attachments": [
{
"type": "fallback",
"payload": {
"url": "<ATTACHMENT_URL >",
"title": "TAHITI - Heaven on Earth"
}
}
]
}
}
]
}
]
}
Are these differences documented elsewhere? Why do they exist in the first place? Why is messaging an array? Can it contain multiple messages at once?

Unable to aggregate multiple collections

I've user collection which has role object which has roleId. I also have roles collection which has id.
Now,for each role, I'd like to get the list of users.
Ex:
[
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
},
{
"name": "Scott",
"role": {
"roleId": "556432"
}
}
]
Roles Data:
[
{
"id": "123432"
"name": "admin",
"type": "internal"
},
{
"id": "556432"
"name": "owner",
"type": "external"
},
{
"id": "556432"
"name": "owner",
"type": "internal"
}
]
Now I want to get all the roles of type internal and their related users:
So, the output should be,
[
{
"role": "123432",
"users": [
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
}
],
{
"role": "556432",
"users": []
}
}
]
I'm doing this with Spring Boot.if someone can help me on how to get this aggregation using spring boot mongo, that'd be very helpful for me. Thank you so much.
Execute aggregate on your role collection and first filter out role as per your condition. Since you want all internal roles, your match stage should be:
{
$match: {
"type": "internal"
}
}
Now its time to lookup users for each role:
{
$lookup: {
from: "user",
as: "users",
localField: "id",
foreignField: "role.roleId"
}
}
I don't know how mongo queries are executed on spring boot but this is how its done on mongo so you can convert it to your language specific code.
Here's a working example on mongo playground.
https://mongoplayground.net/p/I1FPuX971YZ

Only return hits in array from mongodb

So I have a mongodb collection with some nested documents. An example document looks like this:
{
"_id": "5afa9472e937b7254a306ff6",
"import_date": "2018-05-15T08:04:02.813Z",
"some_more_things": "foo",
"meta": {
"participants": [{ "name": "Ben" }, { "name": "Mary" }],
"messages": [
{
"tokens": [
{ "token": "What" },
{ "token": "do" },
{ "token": "you" },
{ "token": "do" },
{ "token": "today" }
],
"time": "2018-05-09T08:38:19.000Z"
},
{
"tokens": [
{ "token": "Just" },
{ "token": "lying" },
{ "token": "around" }
],
"time": "2018-05-09T08:40:08.000Z"
},
{
"tokens": [
{ "token": "What" },
{ "token": "about" },
{ "token": "you" }
],
"time": "2018-05-09T08:40:11.000Z"
}
]
}
}
I'm now looking for an effective way to search for messages where a specific token is included. I'm doing this with following query:
db.conversations.find({'meta.messages.tokens.token': /^What$/i})
.projection({'import_date': 1, 'meta.messages': 1})
.sort({_id:-1})
.limit(100)
That way I find the docs I want but I get the complete messages array. Is there a way that I can get only the items of the messages array matching with my regexp? The result should look like this (so only the first and last item of my example doc).
{
"_id": "5afa9472e937b7254a306ff6",
"import_date": "2018-05-15T08:04:02.813Z",
"meta": {
"participants": [{ "name": "Ben" }, { "name": "Mary" }],
"messages": [
{
"tokens": [
{ "token": "What" },
{ "token": "do" },
{ "token": "you" },
{ "token": "do" },
{ "token": "today" }
],
"time": "2018-05-09T08:38:19.000Z"
},
{
"tokens": [
{ "token": "What" },
{ "token": "about" },
{ "token": "you" }
],
"time": "2018-05-09T08:40:11.000Z"
}
]
}
}
You can use $indexOfBytes to check if What exists in every string. You also need $map with $filter and $anyElementTrue to build your filtering condition for nested array:
db.collection.aggregate([
{
$addFields: {
"meta.messages": {
$filter: {
input: "$meta.messages",
as: "m",
cond: {
$anyElementTrue: {
$map: {
input: "$$m.tokens",
in: { $gte: [ { $indexOfBytes: [ "$$this.token", "What" ] }, 0 ] }
}
}
}
}
}
}
}
])
Mongo Playground
If you need Regex you can take a look at $regexMatch introduced in 4.2 and use it as replacement for $indexOfBytes

Using a structured query to fetch values based on key in array

In my firestore I have a document structured as shown below.
I am trying to set up a Zapier Zap that will allow me to fetch the store name, based on the storeId. It requires a JSON structured query that fetches the data.
Is it possible to do, and where should I begin, I find the documentation lacking examples. The only query I have right now is as shown below, but obviously, it does not work since all data is in a single document.
"where": {
"fieldFilter": {
"field": {
"fieldPath": "stores/*/storeId"
},
"op": "EQUAL",
"value": {
"stringValue": "def"
}
}
}
Document structure
{
"stores": {
"0": {
"storeId": "abc",
"name": "Store 1"
},
"1": {
"storeId": "def",
"name": "Store 2"
}
}
}
I don't think you can do this with an array field, but you can if you change that array to a map field. Something like this:
mycollection/mydoc
{
"someotherfield": "foo",
"stores": {
"abc": {
"name": "Store 1"
},
"def": {
"name": "Store 2"
}
}
}
Now you can use a field mask:
GET https://firestore.googleapis.com/v1/projects/MY-PROJECT/databases/(default)/documents/mycollection/mydoc?mask.fieldPaths=stores.abc.name
Response:
{
"name": "projects/MY-PROJECT/databases/(default)/documents/mycollection/mydoc",
"fields": {
"stores": {
"mapValue": {
"fields": {
"abc": {
"mapValue": {
"fields": {
"name": {
"stringValue": "Store 1"
}
}
}
}
}
}
}
},
"createTime": "2019-04-20T19:14:01.792855Z",
"updateTime": "2019-04-22T18:07:05.660561Z"
}