MongoDB update query (update an array field in document) - php

Here's what the document looks like now.
Array
(
[email] => admin#mysite.com
[emailQueries] => Array
(
[0] => Array
(
[21] => 0
)
[1] => Array
(
[21] => 0
)
)
[last_visit] => 1375050871
)
Here's the code I am using to populate the emailQueries
$arrayValueToAdd = array( (string) $email_id => '0' );
$collection->update( array('email' => $user['email']),
array( '$push' =>
array( 'emailQueries' => $arrayValueToAdd )
)
);
However, I'd like to simply have the emailQueries array look like:
[emailQueries] => Array
(
[21] => 0
[22] => 0
)
Probably a simple thing I'm overlooking...

You are using the array operator push with a data structure that is not considered by MongoDb as an array (array must have 0-based ascending numeric indexes). You must treat it as an object.
So you have 2 choices.
If in [21] => 0, the value 0 is useless (and I don't expect so), you can use a true array:
"emailQueries" : [21,22]
and you can use the push operator in the PHP code like this
$collection->update( array('email' => $user['email']),
array( '$push' =>
array( 'emailQueries' => (string) $email_id )
));
On the other hand, if you must keep the value 0, and for instance, increment it, you have to considered your EmailQuery as an object :
"emailQueries" : {
"21" : 0,
"22" : 0
}
So you can use a simple update to add field in emailQueries :
$collection->update( array('email' => $user['email']),
array( '$set' =>
array( 'emailQueries.'.$email_id => 0 )
));
And the $inc, for incrementation :
$collection->update( array('email' => $user['email']),
array( '$inc' =>
array( 'emailQueries.'.$email_id => 1 )
));

Related

PHP Match by common key of two multidimentional array and merge the two array with both array key [duplicate]

This question already has answers here:
PHP merge two arrays on the same key AND value
(5 answers)
Closed 4 years ago.
Good evening, I have a little bit problem. I have two array. like
$firstArr = Array(
[0] => Array(
[customer_id] => 11,
[home_delivery] => no,
),
[1] => Array(
[customer_id] => 12,
[home_delivery] => no,
),
[2] => Array(
[customer_id] => 13,
[home_delivery] => no,
),
);
$secondArr = Array(
[0] => Array(
[customer_id] => 11,
[test] => no,
[is_active] => yes,
),
[1] => Array(
[customer_id] => 22,
[test] => no,
[is_active] => yes,
),
);
Now i want to get the result like first array's customer_id match with the second array customer_id. Id two array's customer id is same the the value of second array add with first array otherwise the value will be null. Hope guys you got my point what i want. The output which i want is like the below.
$getResult = Array(
[0] => Array(
[customer_id] => 11,
[home_delivery] => no,
[test] => no,
[is_active] => yes,
),
[1] => Array(
[customer_id] => 12,
[home_delivery] => no,
[test] => '',
[is_active] => '',
),
[2] => Array(
[customer_id] => 13,
[home_delivery] => no,
[test] => '',
[is_active] => '',
),
);
I have tried by this code, but it doesnt work. Please help me.
$mergedArray = array();
foreach ($firstArr as $index1 => $value1) {
foreach ($secondArr as $index2 => $value2) {
if ($array1[$index1]['customer_id'] == $array2[$index2]['customer_id']) {
$mergedArray[] = array_merge($firstArr[$index1], $secondArr[$index2]);
}
}
}
echo "<pre>"; print_r($mergedArray); echo "</pre>";
You can do this :
<?php
$results = [];
// Get all unique keys from both arrays
$keys = array_unique(array_merge(array_keys($firstArr[0]), array_keys($secondArr[0])));
// Make array of common customer_ids
foreach (array_merge($firstArr, $secondArr) as $record) {
$results[$record['customer_id']] = isset($results[$record['customer_id']]) ? array_merge($results[$record['customer_id']], $record) : $record;
}
// Fill keys which are not present with blank strings
foreach ($keys as $key) {
foreach ($results as $index => $result) {
if(!array_key_exists($key, $result)){
$results[$index][$key] = '';
}
}
}
print_r($results);
This is how I would do it:
$firstArr = array (
0 =>
array (
'customer_id' => 11,
'home_delivery' => 'no'
),
1 =>
array (
'customer_id' => 12,
'home_delivery' => 'no'
),
2 =>
array (
'customer_id' => 13,
'home_delivery' => 'no'
)
);
$secondArr = array (
0 =>
array (
'customer_id' => 11,
'test' => 'no',
'is_active' => 'yes'
),
1 =>
array (
'customer_id' => 22,
'test' => 'no',
'is_active' => 'yes'
)
);
$secondKey = array_column($secondArr,'customer_id');
foreach($firstArr as &$value){
$idx2 = array_search($value['customer_id'], $secondKey);
$value = array_merge($value, [
'test' => false !== $idx2 ? $secondArr[$idx2]['test'] : '',
'is_active' => false !== $idx2 ? $secondArr[$idx2]['is_active'] : '',
]);
}
print_r($firstArr);
Output:
Array
(
[0] => Array
(
[customer_id] => 11
[home_delivery] => no
[test] => no
[is_active] => yes
)
[1] => Array
(
[customer_id] => 12
[home_delivery] => no
[test] =>
[is_active] =>
)
[2] => Array
(
[customer_id] => 13
[home_delivery] => no
[test] =>
[is_active] =>
)
)
Sandbox
There are 2 "tricks" I use here, the first, and more important one, is array_column this picks just one column from an array, but the thing is the keys in the resulting array will match the original array. Which we can take advantage of.
The array we get from array column looks like this:
array (
0 => 11,
1 => 22
);
Because the keys match the original array we can use array_search (with the ID) to look up that key, which we can then use in the original array. This gives us an "easier" way to search the second array by flattening it out.
So for example when we look up $firstArr['customer_id'] = 11 in the above array we get the key 0 (which is not boolean false, see below). Then we can take that index and use it for the original array $secondArr and get the values from the other 2 columns.
-Note- that array search returns boolean false when it cant find the item, because PHP treats 0 and false the same we have to do a strict type check !== instead of just !=. Otherwise PHP will confuse the 0 index with being false, which is not something we want.
The second "trick" is use & in the foreach value, this is by reference which allows us to modify the array used in the loop, directly. This is optional as you could just as easily create a new array instead. But I thought I would show it as an option.

How to get distance with $near?

I can get my elements, with the following code :
$lines = $loc->find(
array("loc" =>
array('$near' =>
array('$geometry' =>
array('type' => 'Point', 'coordinates' =>
array(floatval($longitude), floatval($latitude))
),
'$maxDistance' => 10000 //meters
)
)
)
);
This is the results :
Array
(
[_id] => MongoId Object
(
[$id] => 5490003c815289663d8bbd95
)
[name] => My adress
[loc] => Array
(
[type] => Point
[coordinates] => Array
(
[0] => 5.050948
[1] => 45.040419
)
)
)
But now, I need to get the distance from my given point.
Is it possible ?
EDIT :
This is the code used to insert datas :
$loc = $client->localisation->localisation;
$loc->ensureIndex( array("loc" => "2dsphere"));
$loc->insert(
array(
"idobject" => $myValue
"name" => $myName
"loc" => array("type" => "Point", "coordinates" => array($longitude, $latitude))
));
The $near operator does not return a distance along with the returned results. It only orders the documents in the response.
Under the PHP driver the easiest form is to use the $geoNear aggregation pipeline stage instead. This allows you to project a field in the results, or even use it in other pipeline stages:
$loc->aggregate(
array(
array(
'$geoNear' => array(
'near' => array(
'type' => 'Point',
'coordinates' =>array(floatval($longitude), floatval($latitude))
),
'maxDistance' => 1000,
'distanceField' => 'distance',
'spherical' => true
)
)
)
);
There is is a database command form for geoNear as well, but direct command results are often not as nice.

mongodb - php - aggregate projection and match

I'm trying to match criteria (cl=1) and then aggregate all the results by month (I've tried year/month/date as well to no luck).
When I run the code below it seems like it works properly, the output shows the months etc, however none of the stats are being added.
The $du field in Mongo is a MongoDate object.
Does anyone have any idea what I'm doing wrong?
See very bottom for a code snippet that is searched by date and returns a result.
$result = $collection->aggregate(
array(
array('$match' => array(
'cl' => $app_id) # application id, int such as "2"
),
array('$project' => array(
//'year' => array('$year' => '$du'),
'month' => array('$month' => '$du'),
//'week' => array('$week' => '$du'),
)),
array('$group' =>
array(
'_id' => array(
'month' => '$month',
),
'i' => array('$sum' => '$vs.i'),
'r' => array('$sum' => '$vs.r'),
'u' => array('$sum' => '$vs.u'),
)
),
array(
'$sort' => array(
'_id' => -1
)
),
array(
'$limit' => 14
)
)
);
Output:
Array
(
[result] => Array
(
[0] => Array
(
[_id] => Array
(
[month] => 10
)
[i] => 0
[r] => 0
[u] => 0
)
[1] => Array
(
[_id] => Array
(
[month] => 9
)
[i] => 0
[r] => 0
[u] => 0
)
.......
working - searching by date
$start = new MongoDate(strtotime("2012-10-01 00:00:00"));
$end = new MongoDate(strtotime("2013-10-15 00:00:00"));
$cursor = $collection->find(array("du" => array('$gt' => $start, '$lte' => $end)));
while ($cursor->hasNext()) {
$document = $cursor->getNext();
print_r($document);exit;
}
# RESPONSE
Array
(
[_id] => MongoId Object
(
[$id] => 51acbfd33dd49497848a8e5b
)
[cl] => 1
[du] => MongoDate Object
(
[sec] => 1370275795
[usec] => 0
)
[vs] => Array
(
[i] => 11
[u] => 1
)
)
The stats aren't there because you haven't chosen to project them. Project gives you _id by default, but anything else you want must be specified.
You'll need something like this instead of your current $project:
array('$project' => array(
'month' => array('$month' => '$du'),
'vs' => 1
))

MongoDB + PHP: How to push item to array with a spcecific key?

In MongoDB-PHP I am using the following example code to push a new entry to the end of an array inside a collection...
$data = array(
"domain"=>"superduperyoyo.com",
"number"=>123,
"week"=>5,
"year"=>2012
);
$db->domains->save(
array( 'someid' => $someid),
array( '$push' => array( 'data' => $data ))
);
This returns keys like 0,1,2,3....
ie.
[someid] => somesupercoolid123
[data] => Array
(
[0] => Array
(
[domain] => superduperyoyo.com
[number] => 123
[week] => 5
[year] => 2012
)
[1] => Array(...)
[2] => Array(...)
)
What I want to do is store YearWeekNumber as the key like this...
[someid] => somesupercoolid123
[data] => Array
(
[201205123] => Array
(
[domain] => superduperyoyo.com
[number] => 123
[week] => 5
[year] => 2012
)
[201206123] => Array(...)
[201207123] => Array(...)
)
How do you save/update the key along with the new entry? I am assuming you can't use $push. That you just use .save or .update but how do you pass the key?
You'd do this by using $set:
$data = array(
"domain"=>"superduperyoyo.com",
"number"=>123,
"week"=>5,
"year"=>2012
);
$db->domains->update(
array( 'someid' => $someid),
array( '$set' => array( 'data' => array( 201205123 => $data )))
);
I would however not recommend doing this. It's better to set another key with this "201205123" value as otherwise you wouldn't be able to do range queries on this value or set an index.
$data = array(
"domain"=>"superduperyoyo.com",
"number"=>123,
"week"=>5,
"year"=>2012
);
$update = array(
'$push' => array('data.201205123' => $data )
);

Complex & Confusing PHP Array Calculations

I have set of data that I need help with. I need to make a difficult calculation and array sort through several multidimensional arrays and the logic and syntax is giving me a headache.
Basically what I need it:
an array of keywords
I need to query a database and store some results for each keyword. (ID and Count of keyword matches)
I need to then flip the array around so instead of keywords being the parent element, it's IDs with the count of matches for each keyword within
I need to perform a calculation to get a single number from these number of matches
I need to sort the array so I can see which ID yielded the highest match value in the database, so I can query and output the relevant data.
I know how I am going to do the calculation for the relevancy now, it's just I've only briefly worked with single dimension arrays and I don't know how to syntactically represent what I need with this example. Could anyone give me a hand?
Here is a sample of what I want - not sure if this is syntactically the best way to show you, but hopefully you'll get the picture:
Array
(
[Keywords] => Array
(
["wax"] => Array
(
[ID] => 1
[Match] => 8
[ID] => 2
[Match] => 10
)
["hard"] => Array
(
[ID] => 1
[Match] => 2
[ID] => 2
[Match] => 37
)
)
Then this array would need to be translated to:
Array
(
[ID] => Array
(
["1"] => Array
(
[Keyword] => "wax"
[Match] => 8
[Keyword] => "hard"
[Match] => 10
)
["2"] => Array
(
[Keyword] => "wax"
[Match] => 2
[Keyword] => "hard"
[Match] => 37
)
)
This code:
$arr = array
(
"wax" => array
(
array(
'ID' => 11,
'Match' => 8
),
array(
'ID' => 21,
'Match' => 10
)
),
"hard" => array
(
array(
'ID' => 11,
'Match' => 2
),
array(
'ID' => 21,
'Match' => 37
)
)
);
$byid = array();
foreach($arr as $kw => $res) {
foreach($res as $r) {
$byid[$r['ID']][] = array('Keyword' => $kw, 'Match' => $r['Match']);
}
}
var_export($byid);
gives:
array (
11 =>
array (
0 =>
array (
'Keyword' => 'wax',
'Match' => 8,
),
1 =>
array (
'Keyword' => 'hard',
'Match' => 2,
),
),
21 =>
array (
0 =>
array (
'Keyword' => 'wax',
'Match' => 10,
),
1 =>
array (
'Keyword' => 'hard',
'Match' => 37,
),
),
)
I hope it helps.
You can query the db and create both the arrays by,
$query = "select id, keyword, count(*) as keyword_count from [your table] group by keyword";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)){
$keyword = $row['keyword'];
$id = $row['id'];
$count = $row['keyword_count'];
$first_array["keywords"]["$keyword"] = array('id' => $id, 'match' => $count);
$second_array["id"]["$id"] = array('keyword' => $keyword, 'match' => $count);
}
print_r($first_array);
print_r($second_array);

Categories