MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

La relation hasMany de la bibliothèque Laravel MongoDB 'jenssegers/laravel-mongodb' ne fonctionne pas

J'ai compris par votre autre question, qu'une tâche peut appartenir à plusieurs employés, non ? Vous devriez donc utiliser belongsToMany relation dans votre Task maquette. De plus, votre exemple de collection "task" montre que dans un document employee_id est un tableau et dans l'autre document, il s'agit d'un ObjectId, alors que les deux doivent être des tableaux.

Quoi qu'il en soit, j'ai eu du mal à comprendre cela, mais j'ai vu que vous ne pouvez pas utiliser hasMany comme l'inverse de belongsToMany , car belongsToMany crée un tableau d'identifiants et hasMany ne fonctionne pas bien avec les tableaux. Je dirais que nous aurions besoin de quelque chose comme hasManyInArray , mais quand j'associe un belongsToMany relation, le document "parent" est créé avec un tableau d'identifiants, ce qui m'amène à penser que le parent devrait également utiliser belongsToMany même s'il "n'appartient pas à" mais "a". Ainsi, lorsque vous associez un employé à une tâche comme celle-ci :

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

Le document "employé" finira par avoir un attribut "task_ids" avec le seul identifiant de tâche qu'il devrait avoir. Cela semble donc être la voie à suivre avec Jenssegers :utiliser belongsToMany dans les deux modèles :

Laravel :Modèle :Employé :

<?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 :Modèle :Tâche :

<?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);
    }
}

Et vous utiliseriez ceci comme :

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

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

La seule chose à ce sujet est que lorsque vous regardez la base de données, vous verrez que les documents de vos employés ont un tableau appelé "task_ids", et à l'intérieur, l'identifiant de la seule tâche de chaque employé. J'espère que cela a aidé.

Juste quelques remarques, vous savez que vous n'êtes pas obligé de définir le nom de la clé primaire sur chaque modèle, n'est-ce pas ? Vous n'avez pas besoin de ceci :

protected $primaryKey = '_id';

De plus, vous n'avez pas à définir le nom de la collection (c'est-à-dire protected $collection = 'employee'; ), sauf si vous voulez vraiment qu'ils soient au singulier (par défaut, ils sont au pluriel).

Je me suis levé au milieu de la nuit (il est 3h52 ici) et j'ai vérifié quelque chose sur l'ordinateur, puis j'ai vérifié DONC et j'ai vu votre question, j'espère que cette fois j'ai répondu assez tôt pour vous, nous semblons être dans des fuseaux horaires différents.

Voici les documents que j'ai créés pour les tests :

collecte des employés

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

collection de tâches

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

Avec ces documents, j'obtiens le premier employé comme ceci :

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

Et dans la sortie, nous pouvons voir que l'attribut relations est un tableau :

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 [▶]
          ]
        }
      ]
    }
  ]
}

Le belongsToMany la méthode n'est pas dans le fichier que vous mentionnez car cette classe (c'est-à-dire Jenssegers\Mongodb\Eloquent\Model ) étend la classe Eloquent Model de Laravel, et c'est là que le belongsToMany méthode est.

Ok, cela doit donc être la raison pour laquelle cela ne fonctionne pas pour vous, car les tableaux doivent être des chaînes au lieu d'ObjectIds. Pourquoi est-ce? Comme c'est ainsi que fonctionne la bibliothèque Jenssegers, elle enregistre les identifiants sous forme de chaînes. J'ai aussi trouvé ce comportement étrange, mais c'est comme ça que ça marche. Rappelez-vous que vous êtes supposé pour relier des objets à l'aide de la bibliothèque Jenssegers, et non en créant les données manuellement dans la base de données. Comment pouvez-vous indexer les identifiants ? Créez simplement un index normal dans MongoDB, comme tasks.createIndex({task_ids: 1}) . Voici la documentation sur la création d'index :https://docs .mongodb.com/manual/reference/method/db.collection.createIndex/ . Vous pouvez également créer des index sur les migrations, voici les docs sur les migrations , assurez-vous de lire les les notes de Jenssegers sur les migrations aussi.

Vous pouvez accéder aux tasks une relation comme celle-ci :$employee->tasks; . Vous accédez aux relations en obtenant une propriété portant le même nom que la méthode avec laquelle vous avez déclaré votre relation, donc si vous avez :

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

Vous obtenez la relation en tant que $post->owner; . Voici la documentation sur les relations :https://laravel.com/docs/5.3/eloquent-relationships