1

I'm working with mongodb in laravel using jenssegers driver and i have 3 documents likes this in my db

{ 
"_id" : ObjectId("594dd540bb7de924c0005583"), 
"cliente" : "Luis", 
"tipo" : "Luis", 
"paquete" : "Luis", 
"fecha" : null, 
"fechaE" : null, 
"content" : "fotos", 
"precio" : NumberInt(200), 
"estatus" : NumberInt(2), 
"Abonos" : [
    {
        "Monto" : NumberInt(200), 
        "Fecha" : null
    }, 
    {
        "Monto" : NumberInt(2000), 
        "Fecha" : null
    }, 
    {
        "Monto" : NumberInt(2000), 
        "Fecha" : null
    }
], 
"updated_at" : ISODate("2017-06-24T02:58:08.000+0000"), 
"created_at" : ISODate("2017-06-24T02:58:08.000+0000")}

Im using this Raw query to get que $sum of all "monto" for each document(3 documents).

  public function updatearray(Request $request, $id){
        $works = new work;
      $result = Work::raw(function($collection)
  {
     return $collection->aggregate(array(
            array('$unwind' => '$Abonos'),
            array('$group' =>
            array( "_id" => '$_id',"Monto" => array('$sum' => '$Abonos.Monto'))),
          ));
 });}

I only want to display the results for my current document, is there a way i can match with the current $id?

-- Edit Im getting id from a get method

  public function abono($id){
  $work = work::find($id);
  return view('workabono', compact('work'));
}

and these are the routes that i use

Route::get('works/{work}/abono', [
'as' => 'works.abono', 'uses' => 'WorkController@abono']);
Route::put('works/{work}/', [
'as' => 'works.updateAbono', 'uses' => 'WorkController@updatearray']);
Maitray Suthar
  • 263
  • 2
  • 13
Fernando Preciado
  • 195
  • 2
  • 4
  • 13

1 Answers1

0

You don't even need the $unwind here. Simply $match and $project:

 public function updatearray(Request $request, $id){
        $works = new work;
      $result = Work::raw(function($collection) use($id)
  {
     return $collection->aggregate(array(
            array('$match' => array( '_id' => $id) ),
            array('$project' =>
              array( "Monto" => array('$sum' => '$Abonos.Monto') )
            )
          ));
 });}

The $sum can directly add the elements from the array.

If $id is a string you can cast to ObjectId explicitly,

$id = new \MongoDB\BSON\ObjectID($id);
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • @LuisPreciado The BSON library here is separate to the application namespace. Have you tried just supplying the `$id` value as it is? Depending on where you are getting it from then it it may already be cast as the correct type. Where are you reading that value from? – Neil Lunn Jun 24 '17 at 04:18
  • @LuisPreciado My bad. Forgot the leading slash ``\`` for the global namespace. – Neil Lunn Jun 24 '17 at 04:21
  • Im getting the id from this function in my controller ` public function abono($id){ $work = work::find($id); return view('workabono', compact('work')); }` i tried to supplying it but i get this **object(Illuminate\Database\Eloquent\Collection)#201 (1) { ["items":protected]=> array(0) { } }** – Fernando Preciado Jun 24 '17 at 04:25
  • @LuisPreciado Please include the code in your question where you are retievieving the value of `$id` from. Sounds like you should not even need to cast, but I need to see the context of the code to be sure. – Neil Lunn Jun 24 '17 at 04:27
  • I still get **Undefined variable : id** My code [link](https://github.com/2014030439/preciado.git) – Fernando Preciado Jun 24 '17 at 04:52
  • @LuisPreciado I'm just looking at that, try removing the `Request $request` since this does seem to imply that the value is not actually being passed through. You could verfiy the actual aggregation operation by simply hardcoding the `ObjectId` into the `$match` statement. But you do actually appear to have a separate issue here which is related to passing in the request parameter to the controller method. – Neil Lunn Jun 24 '17 at 04:58
  • @LuisPreciado So what I'm saying is the MongoDB code is fine. But I don't think you are passing in values correctly. I "think" you should have `Route::put('works/{work}', 'WorkController@updatearray')` and then `public function updateArray($work) { $work = new \MongoDB\BSON\ObjectID($work);` along those lines. And make sure to actually submit a PUT request. But it's not really my bag. I'm just telling you the MongoDB query part. Where passing parameters is the actual new problem, then you should [Ask a new Question](https://stackoverflow.com/questions/ask) instead. – Neil Lunn Jun 24 '17 at 05:13
  • I dont know why i cant use any of my variables in the $match query. i can use it before de raw quey. if i hardcore the ObjectId it works, but its not the result what i want. i will ask a new question. Thanks you – Fernando Preciado Jun 24 '17 at 05:29
  • @LuisPreciado I see it now. You were missing passing in the `$id` for the closure as I found in the [syntax on this question](https://stackoverflow.com/questions/28576524/how-to-pass-variables-tid-id-into-raw-function). Which makes sense, since it would not be in scope for that function unless specified. Coupled with the more efficient aggregation operation shown here this should now work for you. And yes you would seem to need to cast if the value is coming in as a parameter from the URL, as opposed to another source where it was already an `ObjectId`. – Neil Lunn Jun 25 '17 at 00:49