arrayFilters on mongodb php update [duplicate] - php

This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 3 years ago.
I want to update many documents on my db but are nested arrays so I need to use arrayFilters. In the shell works perfect but in my php code never works.
I have tried this way:
$command = new \MongoDB\Driver\Command(
[
'update' => 'students2',
'updates' => [["grades.grade" => ['$gte' => 85]], ['$set' => ["grades.$[elem].mean" => 98 ]], 'arrayFilters' => $filters, 'multi' => true]
]
);
with error: BSON field 'update.updates.grades.grade' is an unknown field
this way:
$db->students2->updateMany([],['$set'=>["grades.$[elem].mean" => 100 ]],['arrayFilters'=> ["elem.grade"=> ['$gte'=>85 ]]]);
with error: "arrayFilters" option has invalid keys for a BSON array
If I execute this command works right but only in one document:
$command = new \MongoDB\Driver\Command(
[
'findAndModify' => 'students2',
'query' => ["grades.grade" => ['$gte' => 85]],
'update' => ['$set' => ["grades.$[elem].mean" => 98 ]],
'upsert' => true,
'returnDocument' => true,
'new' => true,
'arrayFilters' => [['elem.grade'] => ['$gte' => 85]]
]
);
this is my data in mongodb table:
{
"_id" : 1,
"grades" : [
{ "grade" : 80, "mean" : 75, "std" : 6 },
{ "grade" : 85, "mean" : 100, "std" : 4 },
{ "grade" : 85, "mean" : 100, "std" : 6 }
]
}
{
"_id" : 2,
"grades" : [
{ "grade" : 90, "mean" : 100, "std" : 6 },
{ "grade" : 87, "mean" : 100, "std" : 3 },
{ "grade" : 85, "mean" : 100, "std" : 4 }
]
}
What am I doing wrong?
Thanks so much

Try This way
$updateResult = $collection->updateMany(
["inspector" => "J. Clouseau", "Sector" => 4 ],
['$set' => ['Patrolling' => false]]
);

Related

How to check available dates in laravel and mongo

I am developing a hotel booking availability check using laravel and mongodb. I am confused to write query to find available dates. I tried a method but it is like between and. I am not sure query is correct or not.
I have included laravel raw query and mongo query in this question. Both are same.
Why query is not correct?
Because, Guest checking on 2017-09-02 and checkout on 2017-09-05. Currently I am fetching data like 2017-09-02 >= checkin_from && 2017-09-05 <= checkin_from. If 2017-09-02 is the checkin_from date then, this is correct. But if checkin_from is 2017-08-25 and reserve_to is 2017-09-06. Here dates 2017-09-02 to 2017-09-05 includes. In this case how will we check?
Is this possible with query?
Or
Array 1: Fetch all the bookings and store in an array.
Array 2: Then prepare date (checkin and checkout date from frontend) using DatePeriod and DateInterval and store in an array. Then check matching array(1 & 2).
Which method do I follow?
Query Currently I am using
$bookings = Booking::raw(function ($collection) use ($dateBegin, $dateEnd) {
return $collection->aggregate([
[
'$match' => [
'cabinname' => 'test',
'checkin_from' => ['$gte' => $dateBegin, '$lte' => $dateEnd],
'is_delete' => 0,
],
],
[
'$project' => [
'beds' => 1,
'dormitory' => 1,
'sleeps' => 1,
'status' => 1,
'has status' => [
'$in' => ['status', ['1', '4', '5', '7']]
]
],
]
]);
});
Mongo Query
db.booking.aggregate([
{
$match: {
"cabinname" : 'Test',
"checkin_from" : {$gte :[ new Date ('2017-09-01') ], $lte : [ new Date ('2017-09-03') ] },
"is_delete" : 0,
}
},
{
$project: {
"beds" : 1,
"cabinname":1,
"checkin_from":1,
"reserve_to":1,
"has status" : {
$in: [ "status", ['1', '4', '5', '7'] ]
}
}
}
])
Data from database
{ "_id" : ObjectId("5888fbd5d2ae672245fb5f79"), "cabinname" : "Test", "checkin_from" : ISODate("2017-08-29T22:00:00Z"), "reserve_to" : ISODate("2017-09-03T22:00:00Z"), "beds" : "8" }
{ "_id" : ObjectId("58a4812bd2ae67066eeaea41"), "cabinname" : "Test", "checkin_from" : ISODate("2017-09-01T22:00:00Z"), "reserve_to" : ISODate("2017-09-05T22:00:00Z"), "beds" : "18" }
{ "_id" : ObjectId("58bac8a5d2ae67951845edaf"), "cabinname" : "Test", "checkin_from" : ISODate("2017-09-01T22:00:00Z"), "reserve_to" : ISODate("2017-09-02T22:00:00Z"), "beds" : "0" }
{ "_id" : ObjectId("58d03541d2ae671c668b4568"), "cabinname" : "Test", "checkin_from" : ISODate("2017-09-02T22:00:00Z"), "reserve_to" : ISODate("2017-09-04T22:00:00Z"), "beds" : "14" }
My query is not working because of wrong conditions. I have updated the conditions now I am getting exact results.
{checkin_from:{$lte: new Date ('2017-09-02')}, reserve_to:{$gt: new Date ('2017-09-02')}}
$bookings = Booking::raw(function ($collection) use ($dateBegin, $dateEnd) {
return $collection->aggregate([
[
'$match' => [
'cabinname' => 'test',
'checkin_from' => ['$lte' => $dateBegin],
'reserve_to' => ['$gt' => $dateBegin],
'is_delete' => 0,
],
],
[
'$project' => [
'beds' => 1,
'dormitory' => 1,
'sleeps' => 1,
'status' => 1,
'has status' => [
'$in' => ['status', ['1', '4', '5', '7']]
]
],
]
]);
});

How to store object in Mongo DB as value?

Now, when I add values to Mongodb using PHP it stores as array:
{ "_id" : ObjectId("591e9b60470e6c500f3c9869"),"value" : [ "mama", "papa" ] }
How to store data for value as object: {"mama" : 1, "papa" : 2}?
I tried:
$data = array("value" => array("mama" => 1, "papa" => 2))
$this->collection->insert($data);
It is inserted as array!
Try using these lines -
$data = (object) ["value" => (object) ["mama" => 1, "papa" => 2]]
$this->collection->insert($data);
It'll create object with mentioned properties.
db.products.insert(
[
{ _id: 11, item: "pencil", qty: 50, type: "no.2" },
{ item: "pen", qty: 20 },
{ item: "eraser", qty: 25 }
]
)
or
{
"_id" : ObjectId("591c382a82956dc8a500002e"),
"name" : "alpesh",
"email" : "admin#gmail.com",
"contact_number" : "0123456789",
"position" : "devloper",
"updated_at" : ISODate("2017-05-17T11:46:50.000Z"),
"created_at" : ISODate("2017-05-17T11:46:50.000Z")
}

mongodb php: count the number of field in a subdocument

I am using codeigniter with mongodb library https://github.com/intekhabrizvi/Codeigniter-mongo-library
below is my collection "users". I want to count all the badges which has badge_slug = 100_club for userid 57b83ae9faa76bac338b4579 from users collection.
{
"_id" : ObjectId("57b83ae9faa76bac338b4579"),
"displayname" : "test",
"email" : "test#gmail.com",
"badges" : [
{
"awarded_at" : ISODate("2015-04-21T05:52:06Z"),
"object_id" : "",
"badge_slug" : "100_club"
},
{
"awarded_at" : ISODate("2015-04-21T06:12:14Z"),
"object_id" : "",
"badge_slug" : "100_club"
},
{
"awarded_at" : ISODate("2015-04-21T07:09:55Z"),
"object_id" : "",
"badge_slug" : "reader"
}
]
}
what I have done is
$ops = array(
array(
"$project" => array(
"count" => array(
"$size" => array(
"$filter" => array(
"input" => "$badges",
"as" => "badge",
"cond" => array("$eq" => => array("$$badge.badge_slug", "100_club") )
)
)
)
)
),
array(
"$group" => array(
"_id" => null,
"total" => array( "$sum" => "$count" )
)
)
);
$this->mongo_db->aggregate("users", $ops);
So the result should be 2 for given document.
But its returning count for all users. Where should I need to give userid condition?
You can use $match to filter documents before they're passed to next stage.

Join more than one field using aggregate $lookup

I need to join more than two fields in two collections using aggregate $lookup. is it possible to join? please let me know if it is possible. Here i have two collections:
For Example:
"people" collections fields "city,state,country" in "country" collection fields "city_id,state_id,country_id", I want to join this three fields in following collections.
"People"
{
"_id" : 1,
"email" : "admin#gmail.com",
"userId" : "AD",
"userName" : "admin",
"city" : 1,
"state" : 1,
"country" : 1
}
"country"
{
"country_id" : 1,
"userId" : "AD",
"phone" : "0000000000",
"stateinfo":[{
"state_id" : 1,
"state_name" : "State1"
},{
"state_id" : 2,
"state_name" : "State2"
}
],
"cityinfo":[{
"city_id" : 1,
"city_name" : "city1"
},{
"city_id" : 2,
"city_name" : "city2"
}
]
}
This is probably a lot more simple than you think, considering that of course all of the "three" fields are contained within the one "country" document. So it's just a matter of doing the $lookup by "country_id" and then using the retrived content to populate the other fields.
var pipeline = [
{ "$lookup": {
"from": "country",
"localField": "country",
"foreignField": "country_id",
"as": "country"
}},
{ "$project": {
"email": 1,
"userId": 1,
"userName": 1,
"country": {
"$arrayElemAt": [
{ "$filter": {
"input": {
"$map": {
"input": "$country",
"as": "country",
"in": {
"country_id": "$$country.country_id",
"userId": "$$country.userId",
"phone": "$$country.phone",
"stateInfo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$$country.stateInfo",
"as": "state",
"cond": { "$eq": [ "$$state.state_id", "$state" ] }
}},
0
]
},
"cityinfo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$$country.cityinfo",
"as": "city",
"cond": { "$eq": [ "$$city.city_id", "$city" ] }
}},
0
]
}
}
}
},
"as": "country",
"cond": { "$eq": [ "$$country.userId", "$userId" ] }
}},
0
]
}
}}
]
db.people.aggregate(pipeline)
That should give you a result like:
{
"_id" : 1,
"email" : "admin#gmail.com",
"userId" : "AD",
"userName" : "admin",
"country" : {
"country_id" : 1,
"userId" : "AD",
"phone" : "0000000000",
"stateinfo": {
"state_id" : 1,
"state_name" : "State1"
},
"cityinfo": {
"city_id" : 1,
"city_name" : "city1"
}
}
So once the array is matched in by $lookup it all comes down to using $filter to do the matcing and $arrayElemAt to get the first match from each filtered array.
Since the outer array has "inner" arrays, you want to use $map for the "outer" source and apply $filter to each of it's "inner" arrays.
You can get more fancy with $let to get that "reduced" array content down to the returned sub-document and then just directly reference the resulting properties for an even "flatter" response, but the general concept of "matching" the array elements remains the same as above.
For a PHP structure translation:
$pipeline = array(
array(
'$lookup' => array(
'from' => 'country',
'localField' => 'country'
'foreignField' => 'country_id',
'as' => 'country'
)
)
array(
'$project' => array(
'email' => 1,
'userId' => 1,
'userName' => 1,
'country' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => array(
'$map' => array(
'input' => '$country',
'as' => 'country',
'in' => {
'country_id' => '$$country.country_id',
'userId' => '$$country.userId',
'phone' => '$$country.phone',
'stateInfo' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => '$$country.stateInfo',
'as' => 'state',
'cond' => array( '$eq' => array( '$$state.state_id', '$state' ) )
)
),
0
)
),
'cityinfo' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => '$$country.cityinfo',
'as' => 'city',
'cond' => array( '$eq' => array( '$$city.city_id', '$city' ) )
)
),
0
)
)
}
)
),
'as' => 'country',
'cond' => array( '$eq' => array( '$$country.userId', '$userId' ) )
)
),
0
)
)
)
)
);
$people->aggregate($pipeline);
You can usually check your PHP matches a JSON structure when you are working from a JSON example by dumping the pipeline structure:
echo json_encode($pipeline, JSON_PRETTY_PRINT)
And that way you cannot go wrong.
As another final note here, the process after the $lookup is done is quite "complex" even if very efficient. So I would advise that unless there is some need to take this aggregation pipeline further and actually "aggregate" something, then you are probably better off doing that "filtering" in client code rather than doing it on the server.
The client code to do the same thing is far less "obtuse" than what you need to tell the aggregation pipeline to do. So unless this "really" saves you a lot of bandwidth usage by reducing down the matched array, or indeed you if can just "lookup" by doing another query instead, then stick with doing it in code and/or do the seperate query.

How to create this JSON structure in PHP from my data? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have a multiple time series in a MySQL database that I am fetching with PHP
(fetch_assoc) .
Each series has the same X axis but different Y axes.
X axis: datetime (POSIX values).
Y axes:
air_temperature
dew_point_temperature
sea_level_pressure
wind_direction
wind_speed_rate
sky_condition_total_coverage_code
liquid_precipitation_depth_dimension_one_hr
liquid_precipitation_depth_dimension_six_hr
I need to output this data in a specific JSON structure.
Here is an example of the proper end result:
{ "firstRow" : { "beginTime" : "2012-10-09 00:00:01",
"endTime" : "2012-10-10 00:00:00",
"tMax" : "56.0",
"tMean" : "52.5",
"tMin" : "49.0"
},
"interval" : "daily",
"lastRow" : { "beginTime" : "2012-10-15 00:00:01",
"endTime" : "2012-10-16 00:00:00",
"tMax" : "72.0",
"tMean" : "64.0",
"tMin" : "56.0"
},
"series" : [ { "color" : "#FFAE28",
"data" : [ [ 1349740801000,
56
],
[ 1349827201000,
60
],
[ 1349913601000,
69
],
[ 1350000001000,
61
],
[ 1350086401000,
57
],
[ 1350172801000,
56
],
[ 1350259201000,
72
]
],
"name" : "Maximum Temperature (ºF)",
"type" : "spline",
"yAxis" : 0,
"zIndex" : 100
},
{ "color" : "#4bf827",
"data" : [ [ 1349740801000,
52.5
],
[ 1349827201000,
56
],
[ 1349913601000,
59
],
[ 1350000001000,
55.5
],
[ 1350086401000,
49.5
],
[ 1350172801000,
49.5
],
[ 1350259201000,
64
]
],
"name" : "Mean Temperature (ºF)",
"type" : "spline",
"yAxis" : 0,
"zIndex" : 100
},
{ "color" : "#2dc1f0",
"data" : [ [ 1349740801000,
49
],
[ 1349827201000,
52
],
[ 1349913601000,
49
],
[ 1350000001000,
50
],
[ 1350086401000,
42
],
[ 1350172801000,
43
],
[ 1350259201000,
56
]
],
"name" : "Minimum Temperature (ºF)",
"type" : "spline",
"yAxis" : 0,
"zIndex" : 100
}
],
"title" : "New York Laguardia Arpt: Daily Temperature",
"xAxis" : { "max" : 1350259201000,
"maxZoom" : 604800000,
"min" : 1349740801000
},
"yAxis" : { "endOnTick" : false,
"gridLineColor" : "#777",
"gridLineWidth" : 1,
"labels" : { "enabled" : true,
"style" : { "color" : "#eee" }
},
"lineWidth" : 0,
"max" : null,
"maxPadding" : 0,
"min" : null,
"opposite" : false,
"startOnTick" : true,
"tickInterval" : null,
"title" : { "style" : { "color" : "#eee" },
"text" : "Degrees (Fahrenheit)"
}
}
}
Some help with this would be appreciated!
You need to get the data from the database into a php array with the same structure as the javascript representation you want. Then you can use json_encode($arr_data) to create the javascript representation.
In other words, your $arr_data must end up similar to this:
$arr_data = array(
"firstRow" => array(
"beginTime" => "2012-10-09 00:00:01",
"endTime" => "2012-10-10 00:00:00",
"tMax" => "56.0",
"tMean" => "52.5",
"tMin" => "49.0"
),
"interval" => "daily",
"lastRow" => array(
"beginTime" => "2012-10-15 00:00:01",
"endTime" => "2012-10-16 00:00:00",
"tMax" => "72.0",
"tMean" => "64.0",
"tMin" => "56.0"
),
"series" => array(
array(
"color" => "#FFAE28",
"data" => array(
array(1349740801000, 56),
array(1349827201000, 60),
etc...
),
"name" => "Maximum Temperature (ºF)",
"type" => "spline",
etc....
)
)
);
So, you must write a loop to create this php array, maybe something like this (depending on your db fields):
if ($result = $mysqli->query($query)) {
$arr_data = array();
$i = 0;
while ($row = $result->fetch_assoc()) {
$arr_firstRow = array();
$arr_firstRow["beginTime"] = $row["beginTime"];
$arr_firstRow["endTime"] = $row["endTime"];
etc...
$arr_data[$i]["firstRow"] = $arr_firstRow;
$arr_data[$i]["interval"] = $row["interval"];
etc...
$i++;
}
}
And then, you can use json_encode($arr_data).
Have a look at json_encode/json_decode as it will do what you're looking for.
Translation:
JSON=>PHP
json_decode the data and PHP will create the structure using the same outline.
PHP=>JSON
Create the structure using PHP objects then call json_encode to output the information.
If some manipulation needs to be done before you can encode it, you'll have to do it. Judging by the wording of your question the database isn't a direct 1-to-1 translation to JSON (so you'll need to use the data to create the structure first, then pass that structure to the encoder).

Categories