How to read values from nested dataset in TFDMongoQuery - delphi-xe

I'm reading data from a MongoDB. Here is the data:
[{
"_id": "100",
"v": [
{
"length": 1,
"path": "1.txt"
},
{
"length": 2,
"path": "2.txt"
},
{
"length": 3,
"path": "3.txt"
},
{
"length": 4,
"path": "4.txt"
}
]
}]
It is easy to read _id but not 1.txt, 2.txt and 3.txt. Here is my code:
// fdMongQuery = TFDMongoQuery
// dataset = TDataset
fdMongQuery.Close;
fdMongQuery.FieldDefs.Clear;
fdMongQuery.Connection := fdCon;
fdMongQuery.DatabaseName := 'DATABASE';
fdMongQuery.CollectionName := 'COLLECTION';
fdMongQuery.QMatch := '{_id:"100"}';
fdMongQuery.QSort := '';
fdMongQuery.Open;
// read of id
memoLogs.Lines.Add(fdMongQuery.FieldByName('_id').AsString);
// read of detail
dataset := TDataSetField(fdMongQuery.FieldByName('v')).NestedDataSet;
while not dataset.Eof do
begin
memoLogs.Lines.Add(dataset.Fields[0].AsString);
// output is:
// (1, 1.txt)
// (2, 2.txt)
// (3, 3.txt)
dataset.Next;
end;
I am expecting dataset.Fields[0].AsString should ouput 1 while dataset.Fields[1].AsString should output 1.txt but sadly no. So how can I read the path values?

Related

Search by results of previous search in elasticsearch

It is possible to make a search by the results of another search?. For example:
// index: A
{ "ID": 1, "status": "done" }
{ "ID": 2, "status": "processing" }
{ "ID": 3, "status": "done" }
{ "ID": 4, "status": "done" }
// index: B
{ "ID": 1, "user": 1, "value": 10 }
{ "ID": 1, "user": 2, "value": 3 }
{ "ID": 2, "user": 1,"value": 1 }
{ "ID": 3, "user": 1, "value": 3 }
{ "ID": 4, "user": 1, "value": 7 }
Q1: Search in index "A" status == "done" and return the ID
RES: 1,3,4
Q2: From the results in Q1 search value > 5 and return the ID
RES: 1,4
My current solution is use two queries and download the results of "Q1" and make a second search in "Q2" but is very complicated because have 30k of results.
the problem to me seems to be more of a traditional union of filters in 2 indexes sort of a join , what we have in relational databases , not sure of the exact solution but recently had used a plug-in for the joins -> https://siren.io/siren-federate-20-0-introducing-a-scalable-inner-join-for-elasticsearch/ this might help

Laravel - Sort array by string value first and then date

I need help to sort array by couple of logics
[
{
"id": 1,
"status": "pending",
"date": "2019-08-01"
},
{
"id": 2,
"status": "delivered",
"date": "2019-08-01"
},
{
"id": 3,
"status": "pending",
"date": "2019-08-03"
},
{
"id": 4,
"status": "delivered",
"date": "2019-08-03"
},
{
"id": 5,
"status": "delivered",
"date": "2019-08-02"
}
]
what I want to do is to sort the array to status pending show first, and then sort it by the date descending
I already test to using sortByDesc from laravel collection but the array looks like sorted it by just 1 function
$collection = $collection->sortByDesc('date')->sortByDesc(function ($row, $key) {
if($row['status'] == 'pending'){
return 1;
}else{
return 0;
}
});
My expected final result look like this :
[
{
"id": 3,
"status": "pending",
"date": "2019-08-03"
},
{
"id": 1,
"status": "pending",
"date": "2019-08-01"
},
{
"id": 4,
"status": "delivered",
"date": "2019-08-03"
},
{
"id": 5,
"status": "delivered",
"date": "2019-08-02"
},
{
"id": 2,
"status": "delivered",
"date": "2019-08-01"
}
]
Few solutions:
Use a custom callback and return an array source
$products->sortBy(function($product) {
return [$product->param1, $product->param2];
});
This will sort a collection by param2 first, and then by param1
Use a custom callback and return a composite property to sort on source
$posts = $posts->sortBy(function($post) {
return sprintf('%-12s%s', $post->column1, $post->column2);
});
Sort your array by column 1, then split it up by column 2 and then merge it again (untested).
$collection->sortByDesc('date');
$collection->groupBy('status');
$collection->keyBy('status');
EDIT: Also I'm not sure if sortByDesc('date') works with date strings.
Your expected result can be achieved like this.
$sorted = $collection
->sortByDesc('date')
->sortBy(function ($item) {
return 'pending' == $item['status'] ? 0 : 1;
})
->values();
To be more precise:
$collection= $collection->sort(
function ($a, $b) {
if(($a->status== $b->status) &&($a->status== 'pending')){
return ($a->date >= $b->date) ? -1 : 1;
}elseif($a->status== 'pending' && ($a->status!= $b->status)){
return 1;
}else{
return ($a->date <= $b->date) ? 1 : -1;
}
}
);
$collection= $collection->sortByDesc('status');

Number of specific elements in a nested list

An Elastic document has a structure like this:
...
"somefield": "somevalue",
"orders": [{
"version": 1,
"statusCode": 1
}, {
"version": 1,
"statusCode": 1
}, {
"version": 2,
"statusCode": 2
}, {
"version": 3,
"statusCode": 5
}, {
"version": 3,
"statusCode": 6
}
]
...
"orders" is a nested list. I use inline sctipting to calculate the size of the list like this:
"params._source.orders.size() < 4"
I have to add a condition to calculate the number of orders whose statusCode is not 5 and not 6. Linq would look like this:
...orders.Where(o=>!(new[] {5, 6}).Contains(o.statusCode)).size()...
How to write the script in Painless or Groovy?
This results an exeption:
params._source.orders.count { it -> it.statusCode == 1 } < 4
I have found one of the solutions in Painless:
def count = 0;
for (item in params._source.orders){
if (item.statusCode != 5 && item.statusCode != 6) {
count++; }}
return count < 4;

Updating array elements that matches a specific criteria

Let's say I have the following array
var data = [{ id: 0, points: 1 }, { id: 1, points: 2 }]
I would like to update my table which contains
{
"doc-1": {
"id": "abcxyz123",
"entries": [
{ "id": 0, "points": 5 },
{ "id": 1, "points": 3 },
{ "id": 2, "points": 0 }
]
}
}
so that I add the points-field in the data array to the points-field for each element in the "entries" array in "doc-1" that matches the corresponding id in the data array. The end result would look like:
{
"doc-1": {
"id": "abcxyz123",
"entries": [
{ "id": 0, "points": 6 },
{ "id": 1, "points": 4 },
{ "id": 2, "points": 0 }
]
}
}
How do I go about to write such a query in ReQL?
I assume that the actual document in the table looks like this for now:
{
"id": "abcxyz123",
"entries": [{
"id": 0,
"points": 5
}, {
"id": 1,
"points": 3
}, {
"id": 2,
"points": 0
}]
}
That is without the doc-1 nesting.
Then your update can be done like this:
r.table('t1').update(
{
entries: r.row('entries').map(function(e) {
return r.do(r.expr(data)('id').indexesOf(e('id')), function(dataIndexes) {
return r.branch(
dataIndexes.isEmpty(),
e,
{
id: e('id'),
points: e('points').add(r.expr(data)(dataIndexes(0))('points'))
});
});
})
})
I'm using map to map over each entry in entries, and indexesOf to find the corresponding entry in data if it exists.
Note that this doesn't add new entries to the entries list, but only updates existing ones. Please let me know if you need to add new entries as well.
If your documents actually have the doc-1 field first, this query should do the job:
r.table('t1').update(
{ 'doc-1':
{
entries: r.row('doc-1')('entries').map(function(e) {
return r.do(r.expr(data)('id').indexesOf(e('id')), function(dataIndexes) {
return r.branch(
dataIndexes.isEmpty(),
e,
{
id: e('id'),
points: e('points').add(r.expr(data)(dataIndexes(0))('points'))
});
});
})
}
})

Accessing Payloads in Elasticsearch Suggestion

I am currently using the Java API for Elasticsearch.
A suggestion query, returns multiple results 'Suggestion', which I want to be able to iterate over and access the variables. This is done by:
val builder = es.prepareSuggest("companies").addSuggestion(new CompletionSuggestionBuilder("companies").field("name_suggest").text(text).size(count()) )
val suggestResponse = builder.execute().actionGet()
val it = suggestResponse.getSuggest.iterator()
Now
while (it.hasNext()){
val info = it.next()
info.....
}
I need to be able to access info from the payloads from 'info'. An example of the return looks like:
{
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"companies": [
{
"text": "wells",
"offset": 0,
"length": 16,
"options": [
{
"text": "Wells Fargo",
"score": 123.0,
"payload": {
"industry_id": 130,
"id": 776,
"popularity": 123
}
},
{
"text": "Wells Real Estate Funds",
"score": 140.0,
"payload": {
"industry_id": 100,
"id": 778,
"popularity": 123
}
},
{
"text": "Wellstar Health System",
"score": 126.0,
"payload": {
"industry_id": 19,
"id": 1964,
"popularity": 123
}
}
]
}
]
}
When iterating through each suggestion, I seem unable to get the payload. Any ideas as to how I can do this?
To access the payloads, you have to iterate over the Option-Objects. (Right now, you are iterating over the suggestions)
import org.elasticsearch.search.suggest.Suggest.Suggestion
import org.elasticsearch.search.suggest.completion.CompletionSuggestion.Entry
...
// Get your "companies" suggestion
val suggestions: Suggestion[Entry] = suggestResponse.getSuggest.getSuggestion("companies")
val it = suggestions.getEntries.iterator()
// Iterate over all entries in the "company" suggestion
while(it.hasNext) {
val entry = it.next()
val optionsIt = entry.getOptions.iterator()
// Iterate over the options of the entry
while (optionsIt.hasNext) {
val option = optionsIt.next()
// As soon as you have the option-object, you can access the payload with various methods
val payloadAsMap = option.getPayloadAsMap
}
}
I found the information in the tests of ElasticSearch on Github

Resources