how to use $bit operator to query in mongodb with php - php

i have a document like bellow, now i will to figure out which element in friendsR whose readable & 2 is grater than 0. anyone here can help me? thank you.
[code]
$doc = array('friendsR' => array(
array('friend_id'=>100, 'readable' => 7, 'bridge'=>5),
array('friend_id'=>100, 'readable' => 7, 'bridge'=>6),
array('friend_id'=>100, 'readable' => 7, 'bridge'=>7))
);
datamodel()->insert($doc);
$macher = array('$bit' => array( 'friendsR.$.readable' => array('and'=>2) ));
$cursor = datamodel()->find($macher);
[/code]

The $bit operator is an "update operator", so it is used to change values and not query them.
If you need this sort of query you need a JavaScript evaluation such as $where:
For a document that looks like this in the shell:
{
"friendsR": [
{ 'friend_id': 100, 'readable': 7, 'bridge': 5 },
{ 'friend_id': 100, 'readable': 7, 'bridge': 6 },
{ 'friend_id': 100, 'readable': 7, 'bridge': 7 }
]
}
To just find documents that have a matching element you would do this:
$macher = array(
'$where' => new MongoCode("function(){
return this.friendsR.some(function(x) {
return ( x.readable & 2 ) > 0
})
}")
);
To actually return "which elements" matched you would again have to do something like this with mapReduce. It will "mark" which items in the array met the condition and only return documents where at least one array member that matches.
$map = new MongoCode("function(){
this.friendsR.forEach(function(friend) {
friend.macthed = ( ( friend.readable & 2 ) > 0 );
});
if ( this.friendsR.some(function(x) { return x.matched }) )
emit( this._id, this );
}");
$reduce = new MongoCode("function(){}");
$result = $db->command(array(
"mapreduce" => "collection_name",
"map" => $map,
"reduce" => $reduce,
"out" => array( "inline" => 1 )
));
There are no built in operators for bitwise evaluation so JavaScript is your only option where it is available.
Note that the mapReduce is a command and must be run from a Db object, the result is either returned inline as shown or output to another collection. This does not return a cursor. See the official documentation on mapReduce for more information.

Related

laravel - Can I add new items to an array that already has some existing items?

var_export($response) is an array like below:
array (
0 =>
array (
'courseId' => 14,
'tutorName' => 'admin',
),
1 =>
array (
'courseId' => 15,
'tutorName' => 'merl',
),
)
The below code gives a result like this: "data": 3. I wanted add a new item called points with the $response array, into all elements. But here, it overwrites the existing array. How can I achieve this?
$dat=array_push($response,array('points'=>"3"));
return response()->json(['data' => $dat], 200);
Expected output:
[
{
"courseId": 14,
"tutorName": "admin",
"points": 3
},
{
"courseId": 15,
"tutorName": "merl",
"points": 3
}
]
As mentioned, array_push() returns the new number of elements in the array. That's why you get 3.
You can add your value in all elements of the current response, like this:
foreach ($response as $key => $value) {
$response[$key]['points'] = 3;
}
Then, just return the response :
return response()->json($response, 200);

Why is this array_search returning 0

Consider the following:
$characterStats = [
['strength' => 500],
['dexterity' => 200],
['agility' => 1000],
['intelligence' => 1200],
['health' => 675],
];
$stat = array_search(max($characterStats), $characterStats);
echo $stat;
What I expect: ['intelligence' => 1200]
What I get: 0
Can some one help me out to achieve what I want?
Try the following:
$characterStats = array(
'strength' => 500,
'dexterity' => 200,
'agility' => 1000,
'intelligence' => 1200,
'health' => 675,
);
$stat = array_search(max($characterStats), $characterStats);
echo $stat;
I changed the way the array is declared. I believe you may need to indicate the field name you would like to search if using nested arrays with the following call:
$stat = array_search(max($characterStats), array_column($characterStats, 'KEYNAME'));
However, since each sub array has only 1 element with different "key" it may not be the best approach. For your scenario, you may need to use another approach, where you loop through each element and store the max value found.
With the array as you have it at the moment, the easiest way I can think of doing it as a standard foreach() and keep the maximum value as well as the element where it's found (save doing another search to get the full entry)...
$characterStats = [
['strength' => 500],
['dexterity' => 200],
['agility' => 1000],
['intelligence' => 1200],
['health' => 675],
];
$maxStat = null;
$max = null;
foreach ( $characterStats as $stat ){
if ( current($stat) > $max ) {
$max = current($stat);
$maxStat = $stat;
}
}
print_r( $maxStat);

mongodb: update nested document by an array?

I have a deeply nested PHP array which I saved as a document in Mongo and ended up with this structure:
{
"_id" : "...",
"categ1" : {
"aaa" : 112.6736,
"bbb" : 83.9137,
"ccc" : 80.3322,
.....
},
"categ2" : {
"xxx" : 1,
"yyy" : 22,
"zzz" : 7,
"subcateg" : {
"sub1" : 1,
"sub2" : 22
}
}
}
Now, I have another array with a similar structure and I would like to increase the values of the record, by the values of the modifier array:
$modifier=array(
'categ1' => array(
'aaa' => 3,
'bbb' => -1,
'mmm' => 11
),
'categ2' => array(
'yyy' => -2,
'subcateg' => array(
'sub1' => -1
)
)
);
How can I increase the values inside the document by the values of the $modifier all at once, in a single query, and without loading the entire document ?
I've looked around the web but couldn't find any info on this.
Also, i'm pretty newbie at Mongo. Thanks
You can get your $modifier array to look like this:
$modifier = array(
'categ1.aaa' => 3,
'categ1.bbb' => -1,
'categ1.mmm' => 11,
'categ2.yyy' => -2,
'categ2.subcateg.sub1' => -1
)
Link for how to get that.
Then you should be able to simply use:
$col->update(
array("_id" => "..."),
array('$inc' => $modifier),
array("upsert" => true)
);

mongodb: finding the highest numeric value of a column

I have MongoDB collection of documents containing several fields. One of the columns/fields should be numeric only, but some of these fields contain non-numerical (corrupt) data as string values. I should find the highest numerical value of this column, excluding the corrupt, non-numerical data. I am aware of the question Getting the highest value of a column in MongoDB, but AFAIK, this extended case was not covered.
The example below depicts the issue. For the highest value, the document with "age": 70 should be returned:
[
{
"id": "aa001",
"age": "90"
},
{
"id": "bb002",
"age": 70
},
{
"id": "cc003",
"age": 20,
}
]
Providing a PHP example for the find() / findOne() query would be of much help. Thanks a lot!
JohnnyHK came up with the perfect solution. Here's the working PHP code:
$cursor = $collection->find(array('age' => array('$not' => array('$type' => 2))), array('age' => 1));
$cursor->sort(array('age' => -1))->limit(1);
You can use the $type operator with $not in your query to exclude docs where age is a string. In the shell your query would look like:
db.test.find({age: {$not: {$type: 2}}}).sort({age: -1}).limit(1)
Or in PHP from Martti:
$cursor = $collection->find(array('age' => array('$not' => array('$type' => 2))), array('age' => 1));
$cursor->sort(array('price' => -1))->limit(1);
with PHP driver (mongodb)
using findOne()
$filter=[];
$options = ['sort' => ['age' => -1]]; // -1 is for DESC
$result = $collection->findOne(filter, $options);
$maxAge = $result['age']
You can use aggregate function to get maximum number from collections like this.
$data=$collection->aggregate(array
( '$group'=>
array('_id'=>'',
'age'=>array('$max'=>'$age'.)
)
)
);
This works for me
$options = ['limit' => 100,'skip' => 0, 'projection' => ['score' => ['$meta' => 'textScore']], 'sort' => ['score' => ['$meta' => 'textScore']]];

Finding maximum path of a complex array

I have an array:
$data = array(
1 => array(
"time" => 1,
"parent" => array(4)
),
2 => array(
"time" => 3,
"parent" => array(4, 5)
),
3 => array(
"time" => 2,
"parent" => array(6)
),
4 => array(
"time" => 1,
"parent" => array(6)
),
5 => array(
"time" => 1,
"parent" => array(4)
),
6 => array(
"time" => 1,
"parent" => array()
)
);
Key is the ID of an element, parent is an array of elements, which refers to element id and time is just an integer.
This is an illustrated example of a given array:
Schema
The integer on the bottom-left is the "id" and the integer in the middle is "time".
My goal here is find the most time-consuming path of this array. In the given example, the path would be 2->5->4->6 (id wise) resulting in 6 "time" overall. It looks pretty easy on paper, however I can't really seem to code an algorythm to get the elements of the most time-consuming path. I would appreciate any kind of help.
I think the algorythm should be kind of bruteforce-ish and check through all of the options available. Thus with the given array it would go like:
1 -> 4 -> 6 = 3
2 -> 4 -> 6 = 5
2 -> 5 -> 4 -> 6 = 6
3 -> 6 = 3
4 -> 6 = 2
5 -> 4 -> 6 = 3
Thanks in advance.
Note that this will only work if there are no loops in the array.
// Note: built this in the SO editor, might have bugs
$cached = [];
$arrays = []; // Do this yourself
function get_path($num) {
global $arrays, $cached;
if (isset($cached[$num])) return $cached[$num];
$array = $arrays[$num];
$maxtime = $array['time'];
$bestpath = array($num);
foreach ($array['parent'] as $i) {
$path = get_path($i);
if ($path['time']+$array['time'] > $maxtime) {
$maxtime = $path['time'] + $array['time'];
$bestpath = array_merge(array($num),$path['path']);
}
}
$cached[$num] = array('path' => $bestpath, 'time' => $maxtime);
return $cached[$num];
}
var_dump(get_path(5));
Not really a bruteforce way, should be close enough to O(n). The basic idea is that you just cache the paths it can take.
Note: I used a bit of C-style syntax here, but ideally you wouldn't actually write the code like this

Categories