Filter to match array exactly - rethinkdb

My documents contain an array, for example;
{
"a": [ 2, 3 ],
"id": ...
}
I want to return only the documents for which a contains only the elements 2 and 3.
This is the simplest I've found yet;
r.table("t").filter(r.row('a').difference([2,3]).eq([]))
Is there a better way?

A nice way to write the same function would be to use .isEmpty instead of .eq([]).
r.table("t")
.filter(r.row('a').difference([2,3]).isEmpty())
This query is equivalent to the function you wrote.
That being said, your current query returns document where a has only 2 and/or 3. So, for example, a document with with a: [2] would get matched.
Example result set:
{
"a": [ 2 ] ,
"id": "f60f0e43-a542-499f-9481-11372cc386c8"
} {
"a": [ 2, 3 ] ,
"id": "c6ed9b4e-1399-47dd-a692-3db80df4143c"
}
That might be what you want, but if you only want documents where the a property is [2, 3] or [3, 2] exactly and contains no other elements, you might want to just use .eq:
r.table("t")
.filter(r.row('a').eq([2,3]).or( r.row('a').eq([3, 2]) ))
Example result:
{
"a": [ 2, 3 ] ,
"id": "c6ed9b4e-1399-47dd-a692-3db80df4143c"
}, {
"a": [ 3, 2 ] ,
"id": "cb2b5fb6-7601-43b4-a0fd-4b6b8eb83438"
}

Related

Convert an object into an array of objects

i have a simple array of objects like this
{
"a": [1,2],
"b": [3,4]
}
and I want to put it in this form
[
{ "a": 1, "b": 3},
{ "a": 2, "b": 4}
]
I want to find the right approach here.
Seems like this is a transpose operation where a table is given as an object where the keys are the column names and the values is the column data. The output is supposed to be an array of table rows where each row is an object with the column names are its keys.
(
/* define function that iterates over all columns, gets the i-th array index and merges the results */
$getRow := function($x, $i){
$merge($each($x, function($v, $k) {
{$k: $v[$i]}
}))
};
/* this is the first key that is found, "a" in the example */
$firstKey := $.$keys()[0];
/* this is the first column, [1,2] in the example */
$firstArray := $lookup($, $firstKey);
/* loop over the first array (index is $i) and call $getRow($, $i) */
$map($firstArray, function($v, $i){
$getRow($,$i)
} );
)

Elasticsearch with query => 1 Doc with array of 2 values Return 2 hits

Hi I need help writing query.
doc in ES is
{ A: "A", B: ["1","2"] }
result from query should be: hits(2x)
{ A:"A" , B: "1"},
{ A:"A" , B: "2" }
is this possible?

JSON is object instead of array, if array_diff returns assoc array on Collection->toArray()

My issue is in my json I am expecting an array, but am getting an object.
Details:
I have an array of numbers:
$numbers = [1];
I select from relationship, the "drawn numbers":
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
I do a ->toArray() here. I want to find the numbers in $numbers that do not occur in $drawnNumbers. I do so like this:
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
My method then return $numbersNotYetDrawn (my headers accept is application/json).
So now the issue. When $drawnNumbers is an empty array, then the printed json is a regular array like this:
[
1
]
However if the relationship returns $drawnNumbers to be an array with numbers, then json is printed as an object:
{
"0" => 1
}
Does anyone know why this is? Anyway to ensure that json is array?
Edit:
Here is my actual data:
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
$undrawnNumbers = array_diff($numbers, $drawnNumbers);
// $undrawnNumbers = array_values(array_diff($numbers, $drawnNumbers)); // temp fix
Replace
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
with
$numbersNotYetDrawn = array_values(array_diff($numbers, $drawnNumbers));
to make sure element keys are reset and array is treated as a simple list and serialized to a JSON list - instead of being treated as an associative array and serialized to a JSON object.
I recently had this same problem and wondered the same thing.
I solved it by adding "array_values", but I was wondering how to reproduce it.
I found it that it is reproduced when array_diff removes an element from the array that isn't the last element. So:
>>> $x
=> [
1,
2,
3,
4,
5,
]
>>> array_diff($x, [5]);
=> [
1,
2,
3,
4,
]
>>> array_diff($x, [1]);
=> [
1 => 2,
2 => 3,
3 => 4,
4 => 5,
]

Name of sorting algorithm?

I'm trying to figure out the name of a sorting algorithm (or just a method?) that sorts via 3 values.
We start off with 3 values and the array should sort based on the id of the object, position and then the date it was set to that position, allowing both date and position to be the same. Please excuse my horrible explanation. I will give an example.
we have 6 positions, without any edits the array would look something like this
{id:1,pos:0,date:0}
{id:2,pos:0,date:0}
{id:3,pos:0,date:0}
{id:4,pos:0,date:0}
{id:5,pos:0,date:0}
{id:6,pos:0,date:0}
if I was to move the first object to the second position, it would return this order
{id:2,pos:0,date:0}
{id:1,pos:2,date:1}
{id:3,pos:0,date:0}
{id:4,pos:0,date:0}
{id:5,pos:0,date:0}
{id:6,pos:0,date:0}
However if we where to then move the third object into the second position
{id:2,pos:0,date:0}
{id:3,pos:2,date:2}
{id:1,pos:2,date:1}
{id:4,pos:0,date:0}
{id:5,pos:0,date:0}
{id:6,pos:0,date:0}
Note the pos does not change but is ordered before positions of the same number based on the higher date value.
We now move the 4th object into position 1
{id:4,pos:1,date:3}
{id:2,pos:0,date:0}
{id:3,pos:2,date:2}
{id:1,pos:2,date:1}
{id:5,pos:0,date:0}
{id:6,pos:0,date:0}
note id 2 takes the position of number 2 even though pos and date are still 0 because the id is less than the id behind it
We now move id 6 to position 2
{id:4,pos:1,date:3}
{id:6,pos:2,date:4}
{id:2,pos:0,date:0}
{id:3,pos:2,date:2}
{id:1,pos:2,date:1}
{id:5,pos:0,date:0}
id 5 to position 4
{id:4,pos:1,date:3}
{id:6,pos:2,date:4}
{id:2,pos:0,date:0}
{id:5,pos:4,date:5}
{id:3,pos:2,date:2}
{id:1,pos:2,date:1}
And finally id 2 to position 6
{id:4,pos:1,date:3}
{id:6,pos:2,date:4}
{id:5,pos:4,date:5}
{id:3,pos:2,date:2}
{id:1,pos:2,date:1}
{id:2,pos:6,date:6}
I hope my examples aid any response given, I know this is not a question of much quality and if answered I will do my best to edit the question as best I can.
Just a guess, because your final order doesn't look "sorted", lexicographical sort? See Lexicographical order.
The movement of objects is similar to insertion sort, where an entire sub-array is shifted in order to insert an object. The date indicates the order of operations that were performed, and the position indicates where the object was moved to, but there's no field for where an object was moved from. There's enough information to reproduce the sequence by starting with the initial ordering and following the moves according to the date. I don't know if the sequence can be followed in reverse with the given information.
The original ordering can be restored using any sort algorithm using the id field.
I was unfortunately unable to find the name of the 'sort'(?) however, I was able to achieve the effect I was aiming for using the code bellow.
(If I missed something entirely let me know I'll change it and credit you)
PHP Implementation.
$data = '[
{"id":"1","pos":"1","date":"0"},
{"id":"2","pos":"5","date":"0"},
{"id":"3","pos":"4","date":"0"},
{"id":"4","pos":"3","date":"0"},
{"id":"5","pos":"4","date":"1"},
{"id":"6","pos":"2","date":"0"}
]'; //simulated data set
$arr = json_decode($data,true);
$final_arr = $arr;
$tmp_array = array();
$actions = array();
for ($i=0; $i < sizeof($arr); $i++) {
$num = $i+1;
$tmp = array();
for ($o=0; $o < sizeof($arr); $o++) {
if($arr[$o]['pos'] == 0)continue;
if($arr[$o]['pos'] == $num){
array_push($tmp,$arr[$o]);
}
}
if($tmp){
usort($tmp,function($a,$b){
return $a['date'] > $b['date'];
});
for ($o=0; $o < sizeof($tmp); $o++) {
array_push($tmp_array,$tmp[$o]);
}
}
}
for ($i=0; $i < sizeof($tmp_array); $i++) {
for ($o=0; $o < sizeof($arr); $o++) {
if($final_arr[$o]['id'] == $tmp_array[$i]['id']){
array_splice($final_arr, $tmp_array[$i]['pos']-1, 0, array_splice($final_arr, $o, 1));
}
}
}
$output = json_encode($final_arr,JSON_PRETTY_PRINT);
printf($output);
Result:
[
{
"id": "1",
"pos": "1",
"date": "0"
},
{
"id": "6",
"pos": "2",
"date": "0"
},
{
"id": "4",
"pos": "3",
"date": "0"
},
{
"id": "5",
"pos": "4",
"date": "1"
},
{
"id": "2",
"pos": "5",
"date": "0"
},
{
"id": "3",
"pos": "4",
"date": "0"
}
]

How do I query for item with non-empty array with mongoid?

I have the following code that works as expected:
Mongoid::Criteria.new(Question).where(:related_question_ids.size => 0)
However, I would like to perform the query to return questions with related_questions array greater than 0. For example,
Mongoid::Criteria.new(Question).where(:related_question_ids.size.gte => 0)
Is there a way to do this with mongoid or mongodb?
This query search if exists any object in the related_question_ids[0] field
Using js shell
db.questions.find("related_question_ids.0": {exists => true} )
Using mongoid
Mongoid::Criteria.new(Question).where(:"related_question_ids.0".exists => true)
You can search greater any size
Mongoid::Criteria.new(Question).where(:"related_question_ids.3".exists =>true)
This solve your problem
Another way to do this is to use the .nin (Not IN) form of the query:
Mongoid::Criteria.new(Question).where(:related_question_ids.nin => [nil,[]])
This will only return a Question where the related_question_ids is no nil and not an empty array.
Conversely, you can define :related_question_ids to have a default value (:default => []) and then you only need to query for .ne (Not Equal), like so:
Mongoid::Criteria.new(Question).where(:related_question_ids.ne => [])
Either should work.
You can use the $size operator to query by array sizes. Consider the following example using the JS shell:
> db.foo.drop()
> db.foo.insert({_id: 1, x:[1,2]});
> db.foo.insert({_id: 2, x:[]});
> db.foo.insert({_id: 3, x:3});
> db.foo.find({x: {$size: 0}})
{ "_id" : 2, "x" : [ ] }
> db.foo.find({x: {$size: 1}})
> db.foo.find({x: {$size: 2}})
{ "_id" : 1, "x" : [ 1, 2 ] }
> db.foo.find({x: {$not: {$size: 2}}})
{ "_id" : 2, "x" : [ ] }
{ "_id" : 3, "x" : 3 }
> db.foo.find({x: {$not: {$size: 0}}})
{ "_id" : 1, "x" : [ 1, 2 ] }
{ "_id" : 3, "x" : 3 }
I'm not familiar with Mongoid, but I found an example using $size in this documentation.
Two caveats with $size are that it cannot utilize an index (other parts of the query certainly can) and it cannot be used in range queries. If you don't mind the additional bookkeeping, a viable option is to store the array's size in a separate field (likely indexed) and query on that any way you like.

Resources