At http://jsonapi.org/format/#fetching-includes
Articles belongs to an author. Articles have many comments. Comments belongs to a user.
Trying to understand how to include nested relationships. Take for example: https://www.foo.com/articles?include=comments
You would expect:
{
data: [
{
id: 1,
type: "articles",
attributes: { ... },
relationships: {
author: { ... },
comments: [{ ... }, { ... }],
},
...
},
{ ... }
]
included: [
{
author: { ... },
comment: { ... },
comment: { ... }
{
]
}
Now lets say, you wanted to include the users who wrote those comments. https://www.foo.com/articles?include=comments.user
Should the response look like:
{
data: [
{
id: 1,
type: "articles",
attributes: { ... },
relationships: {
author: { ... },
comments: [{ ... }, { ... }]
},
...
},
{ ... }
]
included: [
{
author: { ... },
comment: { ... },
comment: { ... },
user: { ... },
user: { ... }
{
]
}
Should users (users who wrote the comments) also be in the relationship node, or just in the included node?
If in the relationship node. Should user be nested inside data.relationships.comments? How would that look?
According to the Top Level documentation, the included field should be an array of Resource Objects. This means your included field should look like this:
"included": [
{
"type": "author",
"id": ...,
"attributes": { ... },
"relationships": { ... }
}, {
"type": "comment",
"id": ...,
"attributes": { ... },
"relationships": { ... }
}
]
Also according to the Relationships documentation, it should (when side-loading data) contain a Resource Linkage data field which will contain either a single Resource Identifier in the case of a belongsTo relationship, or an array of resource identifier objects in the case of a hasMany relationship.
belongsTo resource identifier:
"relationships": {
"author": {
"links": { ... },
"data": { "type": ..., "id": ... }
},
"comments": {
"links": { ... },
"data": [
{ "type": ..., "id": ... },
{ "type": ..., "id": ... }
]
}
}
Related
I am making a search query in Elastic Search and I want to treat the fields the same when they match. For example if I search for field field1 and it matches, then the _score is increase by 10(for example), same for the field2.
I was tried function_score but it's not working. It throws an error.
"caused_by": {
"type": "class_cast_exception",
"reason": "class
org.elasticsearch.index.fielddata.plain.SortedSetDVOrdinalsIndexFieldData
cannot be cast to class
org.elasticsearch.index.fielddata.IndexNumericFieldData
(org.elasticsearch.index.fielddata.plain.SortedSetDVOrdinalsIndexFieldData
and org.elasticsearch.index.fielddata.IndexNumericFieldData are in unnamed
module of loader 'app')"
}
The query:
{
"track_total_hits": true,
"size": 50,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"term": {
"field1": {
"value": "Value 1"
}
}
},
{
"term": {
"field2": {
"value": "value 2"
}
}
}
]
}
},
"functions": [
{
"field_value_factor": {
"field": "field1",
"factor": 10,
"missing": 0
}
},
{
"field_value_factor": {
"field": "field2",
"factor": 10,
"missing": 0
}
}
],
"boost_mode": "multiply"
}
}
}
You can use function score with filter function to boost.
assuming that your mapping looks like the one below
{
"mappings": {
"properties": {
"field_1": {
"type": "keyword"
},
"field_2": {
"type": "keyword"
}
}
}
}
with documents
{"index":{}}
{"field_1": "foo", "field_2": "bar"}
{"index":{}}
{"field_1": "foo", "field_2": "foo"}
{"index":{}}
{"field_1": "bar", "field_2": "bar"}
you can use weight parameter to boost the documents matched for each query.
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"filter": {
"term": {
"field_1": "foo"
}
},
"weight": 10
},
{
"filter": {
"term": {
"field_2": "foo"
}
},
"weight": 20
}
],
"score_mode": "multiply"
}
}
}
You can refer below solution if you want to provide manual weight for different field in query. This will always replace highest weight field on top of your query response -
Elasticsearch query different fields with different weight
Using : Get
https://smartdevicemanagement.googleapis.com/v1/enterprises/project-id/devices/device-id/
It returns all the info below. i just want the temperature. I am using postnam with: Content-Type and Authorization.
{
"name": "enterprises/c7ad210f-e05d-418c-a52a-1efc0891b3cf/devices/AVPHwEu-AUnrc2QEy_wmf7_u1hXWh_fH2V4q_DA5S1C3_bnLc2H-IxPEsNKtbc5NJZGCXFNAgK9HyZ96slFUQuyShlqauw",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/c7ad210f-e05d-418c-a52a-1efc0891b3cf/structures/AVPHwEsL0trQSBq4GoBJFNrt_eBujz2A9uQvOxg112ZkvUSGMw3A2l3BBFGrLQ-Q8nyc-Mvvqb-Dy6YabT4625fGH1fcIg/rooms/AVPHwEuauRh8KXX1R_kRoTnxKUXRomQ_u80JOyjhfVKKCbn-OPPPigjoAOIJ7kFFwy1-PEs9z6BIP4DugImZLQ2bL59Uv0nZuHLjVsb0If9q0-pGQZcFgY5dxx7iIX63GuIezOW4paE8NNE",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 63
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "HEAT",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 8.82,
"coolCelsius": 24.44443
},
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "CELSIUS"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 16
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 20.23
}
},
"parentRelations": [
{
"parent": "enterprises/c7ad210f-e05d-418c-a52a-1efc0891b3cf/structures/AVPHwEsL0trQSBq4GoBJFNrt_eBujz2A9uQvOxg112ZkvUSGMw3A2l3BBFGrLQ-Q8nyc-Mvvqb-Dy6YabT4625fGH1fcIg/rooms/AVPHwEuauRh8KXX1R_kRoTnxKUXRomQ_u80JOyjhfVKKCbn-OPPPigjoAOIJ7kFFwy1-PEs9z6BIP4DugImZLQ2bL59Uv0nZuHLjVsb0If9q0-pGQZcFgY5dxx7iIX63GuIezOW4paE8NNE",
"displayName": "Hallway"
}
]
}
According to the API documentation, it's not possible to only get the temperature.
But you can get it from the response body you posted, in Postman's test tab:
const resBody = pm.response.json();
temperature = resBody.traits['sdm.devices.traits.Temperature'].ambientTemperatureCelsius;
console.log(temperature);
My sample JSON file for postman runner:
[ { "name": "runner", "hitler_id": "4006abc", "year": "2017", "boolean": "false", "expected": 717962 } ]
Pre request script:
var member = data.name; var booking = data.boolean; var fyyear = data.year; var sid = data.hitler_id;
console.log(data.name); console.log(data.boolean); console.log(data.year); console.log(data.hitler_id);
Body with parameters:
{ "size": 0, "query": { "bool": { "filter": [ { "terms": { "name": [ "{{name}}" ] } }, { "terms": { "salesman_id": [ "{{sid}}" ] } }, { "terms": { "fyyear": [ "{{fyyear}}" ] } }, { "terms": { "boolean": [ "{{boolean}}" ] } } ] } }, "aggs": { "year": { "terms": { "field": "year" }, "aggs": { "value": { "sum": { "field": "value" } } } } } }
For only string variables are accepted - name and boolean fields are working and the value is populated
for the other two, the variable values are not passed.
The variables are not used in your request body that way.
Either you have to store them in environment oder global variables via
pm.globals.set("variable_key", variable_value)
pm.environment.set("variable_key", "variable_value");
or just skip the pre-request script if you just want to use your data and reference the fields directly in your body:
{
"size": 0,
"query": {
"bool": {
"filter": [
{
"terms": {
"name": [
"{{name}}"
]
}
},
{
"terms": {
"salesman_id": [
"{{hitler_id}}"
]
}
},
{
"terms": {
"fyyear": [
{{year}}
]
}
},
{
"terms": {
"boolean": [
{{boolean}}
]
}
}
]
}
},
"aggs": {
"year": {
"terms": {
"field": "year"
},
"aggs": {
"value": {
"sum": {
"field": "value"
}
}
}
}
}
}
However take care you're storing the values in your data file. You stored the bool and the year as strings". But they should be represented as you already did for the "expected" var.
Following up my previous question: ElasticSearch overriding mapping from text to object
I have an index template:
{
"template" : "project.*",
"order" : 100,
"dynamic_templates": [
{
"message_field": {
"mapping": {
"type": "object"
},
"match": "message"
},
"message_properties": {
"path_match": "message.*",
"mapping": {
"type": "string",
"index": "not_analyzed"
}
}
}
]
}
which basically creates new fields for everything under "message" field. I am doing this because "message" field is mapped as a string in another index template and I am overriding it.
Sample document:
{
"level": "30",
...
"kubernetes": {
"container_name": "data-sync-server",
"namespace_name": "alitest03",
...
},
"message": {
"tag": "AUDIT",
"requestId": 1234,
...
},
}
...
}
This works fine, but it ends up creating top level fields like "tag" and "requestId".
I don't want to pollute the top level and would like to have fields like "audit.tag", "audit.requestId".
Tried using copy_to like this, but I don't see any "audit.*" fields:
{
"template" : "project.*",
"order" : 100,
"dynamic_templates": [
{
"message_field": {
"mapping": {
"type": "object"
},
"match": "message"
},
"message_properties": {
"path_match": "message.*",
"mapping": {
"type": "string",
"index": "not_analyzed",
"copy_to" : "audit.{name}"
}
}
}
]
}
A sample search result when using the template above with copy_to is below. I don't see any "audit.*" fields.
{
"timestamp": "October 15th 2018, 15:46:15.994",
"_id": "YmI1NDRjMTgtZTY3Ni00ZGUxLTk2NDMtOTJhZjk3ZWU1YTJj",
"_index": "project.alitestproj02.aa564e69-c643-11e8-af2a-fa163e4c9c9e.2018.10.15",
"_score": "",
"_type": "com.redhat.viaq.common",
...
"kubernetes.container_name": "data-sync-server",
"kubernetes.namespace_name": "alitestproj02",
...
"message": "{\"level\":30,\"time\":1539607575994,\"pid\":19,\"hostname\":\"data-sync-server-6-pxcsm\",\"tag\":\"AUDIT\",\"msg\":\"\",\"requestId\":20355,\"operationType\":\"query\",\"parentTypeName\":\"Meme\",\"path\":\"allMemes.866.owner\",\"success\":true,\"parent\":{\"_type\":\"meme\",\"photourl\":\"photo472\",\"owner\":\"owner35\",\"likes\":0,\"_id\":\"zzEnLAQmQeuTC1mj\",\"createdAt\":\"2018-10-15T11:58:33.896Z\",\"updatedAt\":\"2018-10-15T11:58:33.896Z\",\"id\":\"zzEnLAQmQeuTC1mj\"},\"arguments\":{},\"dataSourceType\":\"InMemory\",\"v\":1}\n",
"requestId": "20355",
"tag": "AUDIT",
...
"v": 1
}
I'm using elasticsearch on AWS to store logs from Cloudfront. I have created a simple query that will give me all entries from the past 24h, sorted from new to old:
{
"from": 0,
"size": 1000,
"query": {
"bool": {
"must": [
{ "match": { "site_name": "some-site" } }
],
"filter": [
{
"range": {
"timestamp": {
"lt": "now",
"gte": "now-1d"
}
}
}
]
}
},
"sort": [
{ "timestamp": { "order": "desc" } }
]
}
Now, there a are certain sources (based on the user agent) for which I would like to exclude results. So my question boils down to this:
How can I filter out entries from the results when a certain field contains a certain string? Or:
query.filter.where('cs_user_agent').does.not.contain('Some string')
(This is not real code, obviously.)
I have tried to make sense of the Elasticsearch documentation, but I couldn't find a good example of how to achieve this.
I hope this makes sense. Thanks in advance!
Okay, I figured it out. What I've done is use a Bool Query in combination with a wildcard:
{
"from": 0,
"size": 1000,
"query": {
"bool": {
"must": [
{ "match": { "site_name": "some-site" } }
],
"filter": [
{
"range": {
"timestamp": {
"lt": "now",
"gte": "now-1d"
}
}
}
],
"must_not": [
{ "wildcard": { "cs_user_agent": "some string*" } }
]
}
},
"sort": [
{ "timestamp": { "order": "desc" } }
]
}
This basically matches any user agent string containing "some string", and then filters it out (because of the "must_not").
I hope this helps others who run into this problem.
nod.js client version:
const { from, size, value, tagsIdExclude } = req.body;
const { body } = await elasticWrapper.client.search({
index: ElasticIndexs.Tags,
body: {
from: from,
size: size,
query: {
bool: {
must: {
wildcard: {
name: {
value: `*${value}*`,
boost: 1.0,
rewrite: 'constant_score',
},
},
},
filter: {
bool: {
must_not: [
{
terms: {
id: tagsIdExclude ? tagsIdExclude : [],
},
},
],
},
},
},
},
},
});