MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Biblioteca Laravel MongoDB 'jensegers/laravel-mongodb' hasMany relacionamento não está funcionando


Eu entendi pela sua outra pergunta, que uma tarefa pode pertencer a muitos funcionários, certo? Então você deve usar belongsToMany relacionamento em sua Task modelo. Além disso, sua coleção de "tarefas" de exemplo mostra que em um documento employee_id é um array e no outro documento é um ObjectId, quando ambos deveriam ser arrays.

De qualquer forma, foi difícil tentar descobrir isso, mas vi que você não pode usar hasMany como o inverso de belongsToMany , porque belongsToMany cria uma matriz de ids e hasMany não funciona bem com matrizes. Eu diria que precisaríamos de algo como hasManyInArray , mas quando associo um belongsToMany relacionamento, o documento "pai" é criado uma matriz de ids, o que me leva a pensar que o pai também deve usar belongsToMany mesmo que não "pertença", mas na verdade "tem". Então, quando você associa um funcionário a uma tarefa como esta:
$task->employees()->save($employee);

O documento "employee" acabará tendo um atributo "task_ids" com o único ID de tarefa que deveria ter. Então esse parece ser o caminho a seguir com Jenssegers:usar belongsToMany em ambos os modelos:

Laravel:Modelo:Funcionário:
<?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:Tarefa:
<?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);
    }
}

E você usaria isso como:
// Give a task a new employee
$task->employees()->save($employee);

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

A única coisa sobre isso é que quando você olhar no banco de dados, você verá que os documentos do seu funcionário possuem um array chamado "task_ids", e dentro dele, o id da única tarefa que cada funcionário possui. Espero que isso tenha ajudado.

Apenas algumas notas laterais, você sabe que não precisa definir o nome da chave primária em cada modelo, certo? Você não precisa disso:
protected $primaryKey = '_id';

Além disso, você não precisa definir o nome da coleção (ou seja, protected $collection = 'employee'; ), a menos que você realmente queira que eles estejam no singular (por padrão, eles estão no plural).

Acordei no meio da noite (são 3:52 da manhã aqui) e verifiquei algo no computador e então verifiquei SO e vi sua pergunta, espero que desta vez tenha respondido em breve para você, parece que estamos em fusos horários diferentes.

Estes são os documentos que criei para teste:

coleção de funcionários
{
    "_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"
    ]
}

coleta de tarefas
{
    "_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"
    ]
}

Com esses documentos recebo o primeiro funcionário assim:
$employee = Employee::with('tasks')->first();
dd($employee);

E na saída podemos ver que o atributo de relações é um array:
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 [▶]
          ]
        }
      ]
    }
  ]
}

O belongsToMany método não está no arquivo que você mencionou porque essa classe (ou seja, Jenssegers\Mongodb\Eloquent\Model ) estende a classe Eloquent Model do Laravel, e é aí que o belongsToMany método é.

Ok, então deve ser por isso que não está funcionando para você, porque os arrays precisam ser strings em vez de ObjectIds. Por que é isso? Porque é assim que a biblioteca Jenssegers funciona, ela salva os Ids como strings. Também achei esse comportamento estranho, mas é assim que funciona. Lembre-se de que você deveria relacionar objetos usando a biblioteca Jenssegers, não criando os dados manualmente no banco de dados. Como você pode indexar os ids? Basta criar um índice normal no MongoDB, como tasks.createIndex({task_ids: 1}) . Aqui está a documentação sobre como criar índices:https://docs .mongodb.com/manual/reference/method/db.collection.createIndex/ . Você também pode criar índices sobre migrações, aqui estão os documentos sobre migrações , certifique-se de ler as notas do Jenssegers sobre migrações também.

Você pode acessar as tasks realtion assim:$employee->tasks; . Você acessa as relações obtendo uma propriedade com o mesmo nome do método com o qual declarou sua relação, portanto, se você tiver:
class Post
{
    public function owner()
    {
        return $this->belongsTo(User::class);
    }
}

Você obtém a relação como $post->owner; . Aqui está a documentação sobre relações:https://laravel.com/docs/5.3/eloquent-relationships