Fauna Search By Ref - faunadb

I have two documents in the products collection...
{
"ref": Ref(Collection("products"), "300137558676865540"),
"ts": 1622492331145000,
"data": {
"product_id": 1004,
"display_name": "Product By ABC",
"description": "Product Description ABC",
"status": "in_stock",
"price_current": 100,
"supplier": Ref(Collection("suppliers"), "300137504766427654")
}
},
{
"ref": Ref(Collection("products"), "300137592998855170"),
"ts": 1622492386360000,
"data": {
"product_id": 1005,
"display_name": "Product By XYZ",
"description": "Product Description XYZ",
"status": "in_stock",
"price_current": 150,
"supplier": Ref(Collection("suppliers"), "300137513423471107")
}
}
then I have also two documents in my suppliers collection...
{
"ref": Ref(Collection("suppliers"), "300137504766427654"),
"ts": 1622492279715000,
"data": {
"supplier_id": 205,
"display_name": "Test Supplier ABC"
}
},
{
"ref": Ref(Collection("suppliers"), "300137513423471107"),
"ts": 1622492287963000,
"data": {
"supplier_id": 206,
"display_name": "Test Supplier XYZ"
}
}
How do I search the products collection by the supplier reference field? Any help is appreciated! Thanks!

All searching in Fauna is done using indexes. You need to create an index for your "products" collection, specifying "supplier" as the search field (aka the terms field in the index):
CreateIndex({
name: "products_by_supplier",
source: Collection("products"),
terms: [{ field: ["data", "supplier"]}]
})
Then you can find all products where the supplier field matches the reference for a specific supplier:
> Paginate(
Match(
Index("products_by_supplier"),
Ref(Collection("suppliers"), "300137504766427654")
)
)
{ data: [ Ref(Collection("products"), "300137558676865540") ] }
If you want to verify that the results are correct, you can iterate over the results to fetch the associated product documents:
> Map(
Paginate(
Match(
Index("products_by_supplier"),
Ref(Collection("suppliers"), "300137504766427654")
)
),
Lambda("X", Get(Var("X")))
)
{
data: [
{
ref: Ref(Collection("products"), "300137558676865540"),
ts: 1622501576960000,
data: {
product_id: 1004,
display_name: 'Product By ABC',
description: 'Product Description ABC',
status: 'in_stock',
price_current: 100,
supplier: Ref(Collection("suppliers"), "300137504766427654")
}
}
]
}
Note that the ts field in my result differs from yours, because I just created those documents.
See the search tutorial for more details: https://docs.fauna.com/fauna/current/tutorials/indexes/search

Related

select node value from json column type

A table I called raw_data with three columns: ID, timestamp, payload, the column paylod is a json type having values such as:
{
"data": {
"author_id": "1461871206425108480",
"created_at": "2022-08-17T23:19:14.000Z",
"geo": {
"coordinates": {
"type": "Point",
"coordinates": [
-0.1094,
51.5141
]
},
"place_id": "3eb2c704fe8a50cb"
},
"id": "1560043605762392066",
"text": " ALWAYS # London, United Kingdom"
},
"matching_rules": [
{
"id": "1560042248007458817",
"tag": "london-paris"
}
]
}
From this I want to select rows where the coordinates is available, such as [-0.1094,51.5141]in this case.
SELECT *
FROM raw_data, json_each(payload)
WHERE json_extract(json_each.value, '$.data.geo.') IS NOT NULL
LIMIT 20;
Nothing was returned.
EDIT
NOT ALL json objects have the coordinates node. For example this value:
{
"data": {
"author_id": "1556031969062010881",
"created_at": "2022-08-18T01:42:21.000Z",
"geo": {
"place_id": "006c6743642cb09c"
},
"id": "1560079621017796609",
"text": "Dear Desperate sister say husband no dey oo."
},
"matching_rules": [
{
"id": "1560077018183630848",
"tag": "kaduna-kano-katsina-dutse-zaria"
}
]
}
The correct path is '$.data.geo.coordinates.coordinates' and there is no need for json_each():
SELECT *
FROM raw_data
WHERE json_extract(payload, '$.data.geo.coordinates.coordinates') IS NOT NULL;
See the demo.

MongoDB multiple Lookup into same collection

I have two collections Bill and Employee. Bill contains the information about the monthly student bill and Employee contains all types of people working in the school (Accountant, Teachers, Maintenance etc).
Bill has billVerifyBy and classteacher field which points to the records of Employees.
Bill collection
{
"_id": ObjectId("ab12dns..."), //mongoid
"studentname": "demoUser",
"class": { "section": "A"},
"billVerifiedBy": "121212",
"classteacher": "134239",
}
Employee collection
{
"_id": ObjectId("121212"), // random number
"name": "Darn Morphy",
"department": "Accounts",
"email": "dantest#test.com",
}
{
"_id": ObjectId("134239"),
"name": "Derreck",
"department": "Faculty",
"email": "derrect145#test.com",
}
I need to retrieve the Accounts and Teacher information related to a particular bill. I am using Mongodb lookup to get the information. However, I have to lookup to the same table twice since billVerifiedBy and classteacher belong to the same Employee tables as given below.
db.bill.aggregate([
{
$lookup: {"from": "employee", "localField": "billVerifiedBy", "foreignField": "_id", "as": "accounts"}},
},
{
$lookup: {"from": "employee", "localField": "classteacher", "foreignField": "_id", "as": "faculty"}},
},
{
$project: {
"studentname": 1,
"class": 1,
"verifiedUser": "$accounts.name",
"verifiedByEmail":"$accounts.email",
"facultyName": "$faculty.name",
"facultyEmail": "$faculty.email"
}
}
]
I don't know if this is the good way of arranging the Accounts and Faculty information in the single Employee collection. And is it right thing to lookup twice with same collection. Or should I create separate Accounts and Faculty collection and lookup with it. Please suggest what would be the best approach in terms of performance.
In mongodb, when you want to join multiple documents from the same collection, you can use "$lookup" with its "pipeline" and "let" options. It filters documents that you want to take with defined variables.
db.getCollection('Bill').aggregate([{
"$lookup": {
"as": "lookupUsers",
"from": "Employee",
// define variables that you need to use in pipeline to filter documents
"let": {
"verifier": "$billVerifiedBy",
"teacher": "$classteacher"
},
"pipeline": [{ // filter employees who you need to filter.
"$match": {
"$expr": {
"$or": [{
"$eq": ["$_id", "$$verifier"]
},
{
"$eq": ["$_id", "$$teacher"]
}
]
}
}
},
{ // combine filtered 2 documents in an employee array
"$group": {
"_id": "",
"employee": {
"$addToSet": {
"_id": "$_id",
"name": "$name",
"department": "$department",
"email": "$email"
}
}
}
},
{ // takes item from the array by predefined variable.
"$project": {
"_id": 0,
"billVerifiedBy": {
"$slice": [{
"$filter": {
"input": "$employee",
"cond": {
"$eq": ["$$this._id", "$$verifier"]
}
}
},
1
]
},
"classteacher": {
"$slice": [{
"$filter": {
"input": "$employee",
"cond": {
"$eq": ["$$this._id", "$$teacher"]
}
}
},
1
]
}
}
},
{
"$unwind": "$billVerifiedBy"
},
{
"$unwind": "$classteacher"
},
]
}
},
{
"$unwind": "$lookupUsers"
},
]);
Output is like that:
{
"_id": ObjectId("602916dcf4450742cdebe38d"),
"studentname": "demoUser",
"class": {
"section": "A"
},
"billVerifiedBy": ObjectId("6029172e9ea6c9d4776517ce"),
"classteacher": ObjectId("6029172e9ea6c9d4776517cf"),
"lookupUsers": {
"billVerifiedBy": {
"_id": ObjectId("6029172e9ea6c9d4776517ce"),
"name": "Darn Morphy",
"department": "Accounts",
"email": "dantest#test.com"
},
"classteacher": {
"_id": ObjectId("6029172e9ea6c9d4776517cf"),
"name": "Derreck",
"department": "Faculty",
"email": "derrect145#test.com"
}
}
}

Couchbase query filtering by tag in an array

I have a author bucket. And in this bucket I keep the author infos and author's articles. I want to select the articles that have the tags I want from the author bucket.
I have tried this but I could not find how to do the filtering.
SELECT art.* FROM author AS a
UNNEST a.articles AS art
WHERE art.tags = 'History'
This is author bucket:
{
"about": {
"name": "sassa",
"userName": "sassatur"
},
"articles": [
{
"authorId": [
"8c7ba33e-0674-4d99-bfad-29d144028bc9"
],
"claps": [],
"comments": [],
"content": {
"articleType": "HTML",
"data": "My First Article"
},
"id": "71d6fa22-61be-4a93-8e86-8d569080da97",
"publishStatus": "UNLISTED",
"statistic": {
"articleId": "71d6fa22-61be-4a93-8e86-8d569080da97",
"views": [
1602683127039,
1602683148270
]
},
"tags": [
"Art, History"
],
"title": "Culture"
},
{
"authorId": [
"8c7ba33e-0674-4d99-bfad-29d144028bc9"
],
"claps": [],
"comments": [],
"content": {
"articleType": "HTML",
"data": "My First Article"
},
"id": "81d6fa22-63be-4a93-8e86-8d569080da97",
"publishStatus": "UNLISTED",
"statistic": {
"views": [
1602683127039,
1602683148270
]
},
"tags": [
"Art"
],
"title": "Culture"
}
],
"id": "8c7ba33e-0674-4d99-bfad-29d144028bc9",
}
Try using ANY/IN/SATISFIES, like so:
SELECT art.* FROM author AS a
UNNEST a.articles AS art
WHERE ANY x IN art.tags SATISFIES x == 'Art' END;
This works for 'Art' in your example, but not 'History' because of the way you are storing tags. It's an array, but it appears to have a single(?) item with comma-separated values. So, instead of "tags": ["Art,History"], I would recommend: "tags": ["Art","History"] instead, and then it will work.
However, if you are stuck with the comma-separate string, you can use SPLIT and ARRAY_CONTAINS as well:
SELECT art.* FROM author AS a
UNNEST a.articles AS art
WHERE ANY x IN art.tags SATISFIES ARRAY_CONTAINS(SPLIT(x,", "), 'History') END;

How to match field value in response when there are multiple fields with the same name?

[
{
"key": "test1",
"category": "test",
"name": "test1",
"translations":
{
"english": "eng"
}
},
{
"key": "test2",
"category": "test",
"name": "test1",
"translations":
{
"english": "eng2",
"german": "German"
}
},
{
"key": "test3",
"category": "power",
"name": "test1",
"translations":
{
"EN_lang": "jik"
}
}
]
Here, we have multiple field's are with different values and we have to match value in translations (field position will change on every call)
You have to be clear about what you want to assert. Hint, the new contains deep (available in 0.9.6.RC4) can help:
* match response contains deep { key: 'test2', translations: { english: 'eng2' } }
Else you should look at transforming the JSON into a shape where it is easier to do the assertions you want: https://github.com/intuit/karate#json-transforms

Transform JSON response with lodash

I'm new in lodash (v3.10.1), and having a hard time understanding.
Hope someone can help.
I have an input something like this:
{
{"id":1,"name":"Matthew","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":2,"name":"Mark","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":3,"name":"Luke","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":4,"name":"John","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}},
{"id":5,"name":"Paul","company":{"id":1,"name":"abc","industry":{"id":5,"name":"Medical"}}}
];
I would like to output this or close to this:
{
"industries": [
{
"industry":{
"id":5,
"name":"Medical",
"companies": [
{
"company":{
"id":1,
"name":"abc",
"employees": [
{"id":1,"name":"Matthew"},
{"id":2,"name":"Mark"},
{"id":3,"name":"Luke"},
{"id":4,"name":"John"},
{"id":5,"name":"Paul"}
]
}
}
]
}
}
]
}
Here's something that gets you close to what you want. I structured the output to be an object instead of an array. You don't need the industries or industry properties in your example output. The output structure looks like this:
{
"industry name": {
"id": "id of industry",
"companies": [
{
"company name": "name of company",
"id": "id of company",
"employees": [
{
"id": "id of company",
"name": "name of employee"
}
]
}
]
}
}
I use the _.chain function to wrap the collection with a lodash wrapper object. This enables me to explicitly chain lodash functions.
From there, I use the _.groupBy function to group elements of the collection by their industry name. Since I'm chaining, I don't have to pass in the array again to the function. It's implicitly passed via the lodash wrapper. The second argument of the _.groupBy is the path to the value I want to group elements by. In this case, it's the path to the industry name: company.industry.name. _.groupBy returns an object with each employee grouped by their industry (industries are keys for this object).
I then do use _.transform to transform each industry object. _.transform is essentially _.reduce except that the results returned from the _.transform function is always an object.
The function passed to the _.transform function gets executed against each key/value pair in the object. In the function, I use _.groupBy again to group employees by company. Based off the results of _.groupBy, I map the values to the final structure I want for each employee object.
I then call the _.value function because I want to unwrap the output collection from the lodash wrapper object.
I hope this made sense. If it doesn't, I highly recommend reading Lo-Dash Essentials. After reading the book, I finally got why lodash is so useful.
"use strict";
var _ = require('lodash');
var emps = [
{ "id": 1, "name": "Matthew", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 2, "name": "Mark", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 3, "name": "Luke", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 4, "name": "John", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } },
{ "id": 5, "name": "Paul", "company": { "id": 1, "name": "abc", "industry": { "id": 5, "name": "Medical" } } }
];
var result = _.chain(emps)
.groupBy("company.industry.name")
.transform(function(result, employees, industry) {
result[industry] = {};
result[industry].id = _.get(employees[0], "company.industry.id");
result[ industry ][ 'companies' ] = _.map(_.groupBy(employees, "company.name"), function( employees, company ) {
return {
company: company,
id: _.get(employees[ 0 ], 'company.id'),
employees: _.map(employees, _.partialRight(_.pick, [ 'id', 'name' ]))
};
});
return result;
})
.value();
Results from your example are as follows:
{
"Medical": {
"id": 5,
"companies": [
{
"company": "abc",
"id": 1,
"employees": [
{
"id": 1,
"name": "Matthew"
},
{
"id": 2,
"name": "Mark"
},
{
"id": 3,
"name": "Luke"
},
{
"id": 4,
"name": "John"
},
{
"id": 5,
"name": "Paul"
}
]
}
]
}
}
If you ever wanted the exact same structure as in the questions, I solved it using the jsonata library:
(
/* lets flatten it out for ease of accessing the properties*/
$step1 := $ ~> | $ |
{
"employee_id": id,
"employee_name": name,
"company_id": company.id,
"company_name": company.name,
"industry_id": company.industry.id,
"industry_name": company.industry.name
},
["company", "id", "name"] |;
/* now the magic begins*/
$step2 := {
"industries":
[($step1{
"industry" & $string(industry_id): ${
"id": $distinct(industry_id)#$I,
"name": $distinct(industry_name),
"companies": [({
"company" & $string(company_id): {
"id": $distinct(company_id),
"name": $distinct(company_name),
"employees": [$.{
"id": $distinct(employee_id),
"name": $distinct(employee_name)
}]
}
} ~> $each(function($v){ {"company": $v} }))]
}
} ~> $each(function($v){ {"industry": $v} }))]
};
)
You can see it in action on the live demo site: https://try.jsonata.org/VvW4uTRz_