sql >> Base de Datos >  >> NoSQL >> MongoDB

La biblioteca Laravel MongoDB 'jenssegers/laravel-mongodb' tiene la relación HasMany no funciona

Entendí por su otra pregunta, que una tarea puede pertenecer a muchos empleados, ¿verdad? Entonces deberías usar belongsToMany relación en su Task modelo. También su colección de "tareas" de ejemplo muestra que en un documento employee_id es una matriz y en el otro documento es un ObjectId, cuando ambos deberían ser matrices.

De todos modos, me ha costado mucho tratar de resolver esto, pero he visto que no puedes usar hasMany como el inverso de belongsToMany , porque belongsToMany crea una matriz de identificadores y hasMany no funciona bien con matrices. Diría que necesitaríamos algo como hasManyInArray , pero cuando asocio un belongsToMany relación, el documento "principal" se crea una matriz de ID, lo que me lleva a pensar que el padre también debería usar belongsToMany a pesar de que no "pertenece a" sino que en realidad "tiene". Entonces, cuando asociaría a un empleado a una tarea como esta:

$task->employees()->save($employee);

El documento "empleado" terminará teniendo un atributo "task_ids" con la única identificación de tarea que debería tener. Ese parece ser el camino a seguir con Jenssegers:usar belongsToMany en ambos modelos:

Laravel:Modelo:Empleado:

<?php
namespace App\Models;

use Jenssegers\Mongodb\Eloquent\Model as Eloquent;

class Employee extends Eloquent
{
    protected $collection = 'employee';

    public function tasks()
    {
        return $this->belongsToMany(Task::class);
    }
}

Laravel:Modelo:Tarea:

<?php
namespace App\Models;

use Jenssegers\Mongodb\Eloquent\Model as Eloquent;

class Task extends Eloquent
{
    protected $collection = 'task';

    public function employees()
    {
        return $this->belongsToMany(Employee::class);
    }
}

Y usarías esto como:

// Give a task a new employee
$task->employees()->save($employee);

// Or give an employee a new task
$employee->tasks()->save($task);

Lo único de esto es que cuando miras la base de datos, verás que los documentos de tus empleados tienen una matriz llamada "task_ids", y dentro de ella, la identificación de la única tarea que tiene cada empleado. Espero que esto haya ayudado.

Solo algunas notas al margen, sabe que no tiene que definir el nombre de la clave principal en cada modelo, ¿verdad? No necesitas esto:

protected $primaryKey = '_id';

Además, no tiene que definir el nombre de la colección (es decir, protected $collection = 'employee'; ), a menos que realmente desee que estén en singular (por defecto, están en plural).

Me levanté en medio de la noche (son las 3:52 a. m. aquí) y revisé algo en la computadora y luego revisé SO y vi su pregunta, espero haber respondido lo suficientemente pronto para usted, parece que estamos en diferentes zonas horarias.

Estos son los documentos que creé para probar:

colección de empleados

{
    "_id" : ObjectId("5870ba1973b55b03d913ba54"),
    "name" : "Jon",
    "updated_at" : ISODate("2017-01-07T09:51:21.316Z"),
    "created_at" : ISODate("2017-01-07T09:51:21.316Z"),
    "task_ids" : [ 
        "5870ba1973b55b03d913ba56"
    ]
},
{
    "_id" : ObjectId("5870ba1973b55b03d913ba55"),
    "name" : "Doe",
    "updated_at" : ISODate("2017-01-07T09:51:21.317Z"),
    "created_at" : ISODate("2017-01-07T09:51:21.317Z"),
    "task_ids" : [ 
        "5870ba1973b55b03d913ba56"
    ]
}

colección de tareas

{
    "_id" : ObjectId("5870ba1973b55b03d913ba56"),
    "name" : "New Task",
    "updated_at" : ISODate("2017-01-07T09:51:21.317Z"),
    "created_at" : ISODate("2017-01-07T09:51:21.317Z"),
    "employee_ids" : [ 
        "5870ba1973b55b03d913ba54", 
        "5870ba1973b55b03d913ba55"
    ]
}

Con estos documentos consigo al primer empleado así:

$employee = Employee::with('tasks')->first();
dd($employee);

Y en la salida podemos ver que el atributo de relaciones es una matriz:

Employee {#186 ▼
  #collection: "employee"
  #primaryKey: "_id"
  // Etc.....
  #relations: array:1 [▼
    "tasks" => Collection {#199 ▼
      #items: array:1 [▼
        0 => Task {#198 ▼
          #collection: "task"
          #primaryKey: "_id"
          // Etc....
          #attributes: array:5 [▼
            "_id" => ObjectID {#193}
            "name" => "New Task"
            "updated_at" => UTCDateTime {#195}
            "created_at" => UTCDateTime {#197}
            "employee_ids" => array:2 [▶]
          ]
        }
      ]
    }
  ]
}

El belongsToMany El método no está en el archivo que menciona porque esa clase (es decir, Jenssegers\Mongodb\Eloquent\Model ) extiende la clase Eloquent Model de Laravel, y ahí es donde belongsToMany el método es.

Ok, esa debe ser la razón por la que no funciona para usted, porque las matrices tienen que ser cadenas en lugar de ObjectIds. ¿Por qué es esto? Debido a que así es como funciona la biblioteca de Jenssegers, guarda los Id. como cadenas. También encontré este comportamiento extraño, pero así es como funciona. Recuerda que se supone para relacionar objetos usando la biblioteca de Jenssegers, no creando los datos manualmente en la base de datos. ¿Cómo puede indexar las identificaciones? Simplemente cree un índice normal en MongoDB, como tasks.createIndex({task_ids: 1}) . Aquí está la documentación sobre cómo crear índices:https://docs .mongodb.com/manual/reference/method/db.collection.createIndex/ . También puede crear índices sobre migraciones, aquí están los documentos sobre migraciones , asegúrese de leer Notas de Jenssegers sobre migraciones también.

Puedes acceder a las tasks relación como esta:$employee->tasks; . Accede a las relaciones obteniendo una propiedad con el mismo nombre del método con el que declaró su relación, por lo que si tiene:

class Post
{
    public function owner()
    {
        return $this->belongsTo(User::class);
    }
}

Obtienes la relación como $post->owner; . Aquí está la documentación sobre relaciones:https://laravel.com/docs/5.3/eloquent-relationships