Filter documents based on value of an attribute inside an array of objects - rethinkdb

RethinkDB newb here and I can't figure this one out.
Lets say I have a table named mydata with documents that have the following basic structure:
{
"SomeAttirbute": "SomeValue",
"team": [
{
"name": "john" ,
"other": "stuff",
} ,
{
"name": "jane" ,
"other": "junk",
}
] ,
...
}
How do I get all documents in the mydata table that have john for a value of the name attribute for any of the elements in the team array?

This is pretty easy and requires a simple ReQL expression. In JavaScript it would be something like this:
const name = 'john';
...
r.db('q50732045')
.table('mydata')
// The predicate below can be literally read as:
// a document whose `team` property is a sequence
// that contains any element with a property `name`
// that equals the given name
.filter(doc => doc('team').contains(member => member('name').eq(name)))
// No need to invoke the run method in Data Explorer
;
I do believe it can be easily re-written in Python.

I think this is what you are looking for:
r.db(insert_database_name).table("mydata").filter(
lambda doc: doc["team"]["name"].contains("john")
).run(con)
or:
r.db(insert_database_name).table("mydata").filter(
r.row["team"]["name"].contains("john")
).run(con)

Related

The filtered result I get by running the filter method on a laravel collection returns a new collection with an undesired index

To make it easier to understand the problem, I will hardcode the data that I am using the collection on and explain the problem.
Let us assume the following data structure in JSON format,
{
"shelters_with_linear_distances": [
{
"id": 3,
"shelterName": "Third Shelter",
"latitude": "5.0034000",
"longitude": "70.1230000",
"linear_distance": 3.1352984845527
},
{
"id": 4,
"shelterName": "Fourth Shelter",
"latitude": "5.1413000",
"longitude": "70.2250000",
"linear_distance": 2.7850629146201
},
{
"id": 5,
"shelterName": "Fifth Shelter",
"latitude": "5.2220000",
"longitude": "70.1320000",
"linear_distance": 2.6042789457753
}
]
}
The following filter method is run on a collection format of 'shelters_with_linear_distance' in the above data structure and $minimum_distance_to_a_shelter is a dynamically calculated value that holds a data type of double.
$nearest_shelter = $shelters_with_linear_distances_from_user
->filter(function ($shelter, $key) use ($minimum_distance_to_a_shelter) {
return $shelter['linear_distance'] == $minimum_distance_to_a_shelter;
});
The problem here is if I send back the value returned by the filter method (which is the $nearest_shelter) as JSON to the frontend,
in the postman I see the following output,
{
"nearest_shelter": {
"2": { // <------------------------------------ I can not figure out from where this key '2' is coming from.
"id": 5,
"shelterName": "Fifth Shelter",
"latitude": "5.2220000",
"longitude": "70.1320000",
"linear_distance": 2.6042789457753
}
}
}
The problem is I can not figure out from where the key I have pointed with an arrow in the above line of code is coming from.
*) It is okay if that value '2' never changes so that in the later parts of code I can always access the $nearest_shelter as $nearest_shelter['2']. But the problem is, the value of that key changes depending on the data I am receiving from the db.
One time that value of the key was '1', then once I added some new records to the db it was '2'. Also this one other time there was no key marked as either '1' or '2' and the shelter I wanted was directly inside the collection.
Can someone please help me understand why this is happening and how to get rid of that since I want to access the value inside the $nearest_shelter in latter parts of the code and I do not want to get a key like that which I do not know the value of beforehand to access the $nearest_shelter later in the code.
(Project I am working on uses laravel 5.2)
Thanks.
When you filter a collection, the index is preserved.
The "2" is because this element was the third (so index 2) in your original collection.
To fix this, just add ->values() after the filter:
$nearest_shelter = $shelters_with_linear_distances_from_user
->filter(function ($shelter, $key) use ($minimum_distance_to_a_shelter) {
return $shelter['linear_distance'] == $minimum_distance_to_a_shelter;
})->values();
This way the index will be reset and will start from 0, as usual.
From the documentation (for Laravel 5.2 as stated in your question) documentation:
The values method returns a new collection with the keys reset to consecutive integers

Elasticsearch dsl python, natural key for document?

I have a document which looks like
{
date_at: '2020-10-01',
foo_id: 3,
value: 5
}
When date_at and foo_id are defined, document is uniquely defined.
So I'd like to do something like
MyDocument.update_or_create(date_at=date_at, foo_id=foo_id, {value: some_value})
If a document with given date_at and foo_id exists, update the document, otherwise create the document.
In order to update or create a document (what ES calls "upsert"), you need to go through the update API and that API requires a document ID.
Selecting a document with a specific date_at and foo_id would be the job of the update by query API but that API doesn't support "upserting" (i.e. create or update).
So, if your documents are uniquely defined by date_at and foo_id, I'd suggest giving them IDs that contain those two values, like for instance 2020-10-01:3. Doing so would allow you to leverage the update API like this:
POST your-index/_update/2020-10-01:3
{
"doc": {
"value": "some_value",
"date_at": "2020-10-01",
"foo_id": 3
},
"doc_as_upsert": true
}
An alternative approach would be creating daily indices and using foo_id as document id. Then upserting would be as simple as:
PUT your-index-2020-10-01/_doc/3
{
"value": "some_value",
"date_at": "2020-10-01",
"foo_id": 3
}
foo_id would be always unique within the index.

Can I directly get a nested list in my Doctrine result?

Sorry if the question is poorly phrased, I couldn't come up with a good way of describing my issue.
So basically, I'm using the Doctrine query builder to try and a list of training sessions from my Session entity. For each session, I need to fetch basic properties such as the name and date, but I also need to fetch the list of participants. There is a one-to-many relation between the entities Session and Participant, as there may be several participants to a given session. I would simply need a list of these participants, nested in each item of the list of sessions. Something like this:
[
{
"session_name": "name1",
"session_date": "date1",
...
"participants": [
{
"participant_name": "john1",
...
},
{
"participant_name": "john2",
...
},
...
],
},
{
"session_name": "name2",
"session_date": "date2",
...
"participants": [
{
"participant_name": "john3",
...
},
{
"participant_name": "john4",
...
},
...
],
},
...
]
This seems to me like it should be quite basic, but for the life of me I cannot get it to work with JOINs, subqueries, etc. The closest I got was this error, which does imply I'm trying to get a nested array (but it won't let me):
SQLSTATE[21000]: Cardinality violation: 1242 Subquery returns more than 1 row
I had this error running this code:
$query = $this->createQueryBuilder('s')
->select('
s.name,
s.date,
(SELECT p.nom FROM '.Participant::class.' p WHERE p.session = s.id) participants
')
->getQuery()->getArrayResult();
I know I could just fetch my sessions, then loop through them and fetch their participants with another DQL query, but obviously that doesn't seem like the proper way to do it. Is there a better way?
You can directly do a leftJoin on your QueryBuilder :
$queryResult = $this->createQueryBuilder('s')
// After that next line, you can reference participants as 'p'
->leftJoin('s.participants', 'p')
// If you intend to loop on the result, to avoid the N+1 problem, add this line :
->addSelect('p')
->getQuery()
->getResult()
;

Is there a way to define attribute type as Keyword in ElasticSearch Array data type?

I am working on indexing a large data set which has multiple name fields for a particular entity. I have defined the name field of type array and I am adding around 4 names in that. Some of the names have spaces in between and they are getting tokenized. Can I avoid that?
I know for String we have text as well as keyword type in Elastic but how do I define the type as keyword when I am having array as my data type? By default all the array fields are taken as text type. I want them to be treated as keyword type so they don't get tokenized while indexing.
Expected : If I store "Hello World" in an array, I should be able to search "Hello World".
Current behavior : It stores hello differently and world differently as it tokenizes that.
There is no data type for array in elastic search. Whenever you send an array as value of a property of type x then that property becomes an array accepting only the values of type x.
So for example you created a property as below:
{
"tagIds": {
"type": "integer"
}
}
And you index a document with values as below:
{
"tagIds": [124, 452, 234]
}
Then tagIds automatically become an array of integers.
For your case all you need to do is create a field say name with type as keyword. And make sure you always pass an array to this field even if it has to hold a single value to make sure it is always an array. Below is what you need:
Mapping:
PUT test
{
"mappings": {
"_doc": {
"properties": {
"name": {
"type": "keyword"
}
}
}
}
}
Indexing document:
PUT test/_doc/1
{
"name" : ["name one"]
}

How to get random row in object variable in Laravel?

Sorry for my bad english, I want to get a single row in my object. And I want that in random order. Im using array_rand() and it only return errors as stated below:
ErrorException: array_rand() expects parameter 1 to be array, object given in file C:\xampp\htdocs\user\TestProject\app\Http\Controllers\TestController.php on line
Here is my object.
"my_list": [
{
"id": 1,
"name": "My Name Test",
"address": [
{
"id": 1,
"city": "Manila",
"country": "Philippines"
}
]
},
{
"id": 2,
"name": "Your Name Test",
"address": [
{
"id": 2,
"city": "Cebu",
"country": "Philippines",
}
]
}
]
The problem is I want only to get a single row to the my_list which is object and not an array.
Here is my code.
$course = Course::where('id', 1)->with('my_list')->first();
$random_list = array_rand($course->my_list);
return $random_list;
I also try adding number of row in the array_rand like this.
$random_list = array_rand($course->my_list, 1);
But still not working.
What did I missed?
Any Eloquent query returns, by default, a Collection, even for the underlying relationships. Since you are working with one, this should work:
$course->my_list->random();
This will return only one item. If you want more, you could pass an argument to the random() method specifying the count of items you want.
For more information, check the documentation.
This Object is a Laravel collection. Please refer to the collection documentation.
https://laravel.com/docs/5.7/collections#method-random
You can try $course->my_list->random()
If you still wanna do this with your approach, can you try get_object_vars function to cast object into array.
$array = get_object_vars($object);
so that you can use them as an array in array_rand.
You might get an error, hence that it's an multi-dimensional array. Let me know so i may update.
Update for multidimensional:
Please refer to this.
// The second parameter of json_decode forces parsing into an associative array
$array = json_decode(json_encode($object), true);
try this:
$course = Course::where('id', 1)
->with(['my_list' => function($query) {
$query->inRandomOrder();
}])->first();
return $course->my_list;
Try this method:
$course = Course::where('id', 1)
->with(['my_list' => function($query) {
$query->inRandomOrder()->first();
}])->first();
return $course->my_list;
this method is more efficient since you will only get 1 row from my_list not like when you use $course->my_list->random() which retrieves all data and from there select a random row.
$random_list = $course['my_list']->random(number);
ps: number = number of element you want to get ,

Resources