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)
);
Related
I am writing a script that loops through a multidimensional array and it's working as hoped (sort of) but I get errors that I just can't remedy.
I am still not that comfortable building loops to manage nested arrays.
Here is my code. The goal is to sort each layer by the value of the sequence key and in the end I export the array as json.
The sequence key may or may not exist in every sub array so that may need some sort of if clause
<?php
$list = [
"key" => "book",
"sequence" => 1,
"items" => [
[
"key" => "verse",
"sequence" => 2,
"items" => [
["sequence" => 3],
["sequence" => 1],
["sequence" => 2],
],
],
[
"key" => "page",
"sequence" => 1,
"items" => [
[
"key" => "page",
"sequence" => 2,
"items" => [
["sequence" => 2],
["sequence" => 1],
["sequence" => 3],
],
],
[
"key" => "paragraph",
"sequence" => 1,
"items" => [
["sequence" => 2],
["sequence" => 1],
["sequence" => 3],
],
],
],
],
],
];
function sortit(&$array){
foreach($array as $key => &$value){
//If $value is an array.
if(is_array($value)){
if($key == "items"){
uasort($value, function($a,&$b) {
return $a["sequence"] <=> $b["sequence"];
});
}
//We need to loop through it.
sortit($value);
} else{
//It is not an array, so print it out.
echo $key . " : " . $value . "<br/>";
}
}
}
sortit($list);
echo "<pre>";
print_r($list);
?>
Here is the output and error I am getting, and I think I understand why the error is being thrown but at the same time I can not implement the proper checks needed to fix the error.
key : book
sequence : 1
key : page
sequence : 1
E_WARNING : type 2 -- Illegal string offset 'sequence' -- at line 39
E_NOTICE : type 8 -- Undefined index: sequence -- at line 39
sequence : 1
sequence : 2
sequence : 3
sequence : 1
key : page
E_WARNING : type 2 -- Illegal string offset 'sequence' -- at line 39
E_NOTICE : type 8 -- Undefined index: sequence -- at line 39
sequence : 1
sequence : 2
sequence : 3
sequence : 2
key : verse
Not that I am worried to much but another thing that I would like is the array to still be structured in the original order, ie: key, sequence, items
Using usort and array references makes it straightforward. If we're dealing with an array with a set item key, sort the item array and recurse on its children, otherwise, we're at a leaf node and can return.
function seqSort(&$arr) {
if (is_array($arr) && array_key_exists("items", $arr)) {
usort($arr["items"], function ($a, $b) {
return $a["sequence"] - $b["sequence"];
});
foreach ($arr["items"] as &$item) {
$item = seqSort($item);
}
}
return $arr;
}
Result:
array (
'key' => 'book',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'key' => 'page',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'key' => 'page',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'sequence' => 1,
),
1 =>
array (
'sequence' => 2,
),
2 =>
array (
'sequence' => 3,
),
),
),
),
),
1 =>
array (
'key' => 'verse',
'sequence' => 2,
'items' =>
array (
0 =>
array (
'sequence' => 1,
),
1 =>
array (
'sequence' => 2,
),
2 =>
array (
'sequence' => 3,
),
),
),
),
)
Try it!
Note that the outermost structure is a root node that isn't part of an array and can't be sorted (this may be unintentional and causing confusion).
i have collection like this
{
"wl_total" : 380,
"player_id" : 1241,
"username" : "Robin",
"hand_id" : 292656,
"time" : 1429871584
}
{
"wl_total" : -400,
"player_id" : 1243,
"username" : "a",
"hand_id" : 292656,
"time" : 1429871584
}
as both collection have same hand_id i want to aggregate both these collection on the basis of hand_id
i want result as combine of
data=array(
'hand_id'=>292656,
'wl_total'=>
{
0=>380,
1=>-400
},
'username'=>
{
0=>"Robin",
1=>"a"
},
"time"=>1429871584
)
You basically want a $group by the "hand_id" common to all players, and then $push to different arrays in the document and then also do something with "time", I took $max. Nees to be an accumulator of some sort at any rate.
Also not sure what your underlying collection name is, but you can call this in laravel with a construct like this:
$result = DB::collection('collection_name')->raw(function($collection)
{
return $collection->aggregate(array(
array(
'$group' => array(
'_id' => '$hand_id',
'wl_total' => array(
'$push' => '$wl_total'
),
'username' => array(
'$push' => '$username'
),
'time' => array(
'$max' => '$time'
)
)
)
));
});
Which returns output ( shown in json ) like this:
{
"_id" : 292656,
"wl_total" : [
380,
-400
],
"username" : [
"Robin",
"a"
],
"time" : 1429871584
}
Personally I would have gone for a single array with all the infomation in it for the grouped "hand", but I supose you have your reasons why you want it this way.
So I am trying to make a JSON object that should hold some information about some questions for me. This is a pseudo-code of how I want it to be presented:
{
"page" : 1,
"info" :
{
"id" : 1,
"type" : 3,
"description": "How to do JSON?",
"alternatives" :
{
"id" : 1,
"description" : "Dunno"
}
{
"id" : 2,
"description" : "Let me show you"
}
{
"id" : 3,
"description" : "I refuse to show you"
}
}
"id" : 2,
"type" : 1,
"description": "Do you get it?",
"alternatives" :
{
"id" : 1,
"description" : "Yes"
}
{
"id" : 2,
"description" : "No"
}
}
}
So the code underneath is from Nightmare (one of the answers), and it does exactly what I want to do with the page and the questions, but I can't seem to figure out how to connect alternatives to each question. You can see a snippet at the bottom where I have tried but it's not correctly spelled and I've been hammering at this for a while now.
$before_json_encode[$row['page']][] = array(
'id' => $row['id'],
'type' => $row['type'],
'description' => $row['description'],
'alternatives' => $alternativesarray//im not sure about here,dont know the structure of the alternative array
);
Another illustration on how I want the hierarchy of the JSON data to appear. I need to be able to pick for instance: All alternatives to all questions on a specific page. So if I want to generate page 3 in my poll I can first find the questions within the page 3 sub-array, and then again from each question gain access to all of it's connected alternatives in that questions's own sub-array. Sorry for the poor explanation of my issue, it's just a bit complicated :/
Page
Question
Alternative
Alternative
Alternative
Question
Alternative
Alternative
Alternative
Question
Alternative
Alternative
Page
Question
Alternative
Alternative
Question
Alternative
Alternative
Update: 3rd layer:
$rows_test2[$r['page']]
['id' => $r['id'],
'type' => $r['type'],
'description' => $r['description']]
[] =
array (
'altid' => $t['altid'],
'altdesc' => $t['altdesc']);
$rows[] = array(
"page" => 1,
"info" => array(
"id" => 1,
"type" => 3,
"description" => 'desc',
)
);
echo json_encode($rows); // [{"page":1,"info":{"id":1,"type":3,"description":"desc"}}]
Update:
$alternativesarray[]=array('id'=>'1', 'description'=>'yes');
$alternativesarray[]=array('id'=>'2', 'description'=>'no');
$rows[] = array(
"page" => 1,
"info" => array(
"id" => 2,
"type" => 3,
"description" => 'desc',
"alternatives" => $alternativesarray
)
);
print json_encode($rows); // [{"page":1,"info":{"id":2,"type":3,"description":"desc","alternatives":[{"id":"1","description":"yes"},{"id":"2","description":"no"}]}}]
maybe like this?
$before_json_encode[$row['page']][] = array(
'id' => $row['id'],
'type' => $row['type'],
'description' => $row['description'],
'alternatives' => $alternativesarray//im not sure about here,dont know the structure of the alternative array
);
Trying to push some data to record using php
array('$push' => array(
"value" => 1,
"comment" => $data['comment'],
"status" => 1,
))
But in db I see following records like array :
And it's should be like a normal values :
Seems that you want to use $set instead of $push.
array('$set' => array(
"value" => 1,
"comment" => $data['comment'],
"status" => 1,
))
$push is for appending elements to embedded arrays. $set is for replacing field values.
Trying to do a simple mongodb query that drives me mad.... I have the following table/db:
[_id] => MongoId Object (
[$id] => 4f22efa1ef9dec8495b374bc
)
[h1] => a
[h2] => b
[h3] => c
[_id] => MongoId Object (
[$id] => 4f22efa1ef9dec8495b374bd
)
[h1] => d
[h2] => e
[h3] => f
Using the mongo tool command line and typing:
db.things.find({$or: [{'h1' : 'a'},{'h1': 'd'}]})
I get:
{ "_id" : ObjectId("4f22efa1ef9dec8495b374bc"), "h1" : "a", "h2" : "b", "h3" : "c" }
{ "_id" : ObjectId("4f22efa1ef9dec8495b374bd"), "h1" : "d", "h2" : "e", "h3" : "f" }
Which is fine. However trying doing the same from PHP, I get nothing ??:
$m = new Mongo();
$db = $m->selectDB('testdb');
$collection = new MongoCollection($db, 'things');
$query = array( '$or' => array( array('h1' => 'a')),
array('h1' => 'd'));
$cursor = $collection->find($query);
I do not see what I am doing wrong, but I have tried anything (or I think so) for 3 days now and it will not work. If I do queries using '>=' '<=' '<>' '<' '>' it works fine but using '=' as in this case it does not.
Thanks for your effort !
You're better off using $in for your given example, i.e.:
$collection->find(array('h1' => array('$in' => array('a', 'd'))));
As to why your query doesn't work - you're not using $or correctly (or infact, at all). This is the query you've put in the question reformatted:
$query = array(
'$or' => array(
array('h1' => 'a')
),
array('h1' => 'd')
);
Whereas you would need:
$query = array(
'$or' => array(
array('h1' => 'a'),
array('h1' => 'd')
)
);
If you have a look in the mongodb error log most likely it says something about that illegal loose top-level array in the conditions.