Laravel Eloquent 查询同一个 table 中的兄弟姐妹并预先加载

Laravel Eloquent query siblings in same table with eager loading

我有一个名为 patients 的父 table,它与一个名为 notes 的子 table 具有一对多关系。 (即一位患者可以有多个笔记)。如果给出注释,我想为同一患者找到其他注释。注释通过名为 patient_id.

的 fk 与患者相关

在 SQL 中,我会这样做:

SELECT * FROM notes WHERE patient_id={note.patient_id} AND id <> {note.id}

在 Eloquent 中,我有这个:

class Note extends Model
{

    public function otherEncounterNotes()
    {
        return $this->hasMany('App\Note', 'patient_id', 'patient_id')->where('id', '<>',$this->id);
    }
...

在我的数据库中,id=1 的患者有两个 id 为 1 和 2 的笔记,所以如果我查找笔记 id 1 的兄弟姐妹,我应该得到笔记 id 2。

当我使用 find() 时,它按预期工作,但是当我使用 where() 时,它 returns 原始音符而不是同级音符。有什么想法吗?

>>> Note::find(1)->otherEncounterNotes->pluck('id')                                                                                                                                                                             
=> Illuminate\Support\Collection {#5542
     all: [
       2,
     ],
   }

>>> Note::where('id',1)->with('otherEncounterNotes')->pluck('id')                                                                                                                                                               
=> Illuminate\Support\Collection {#5526
     all: [
       1,
     ],
   }

给定一个 Note id,你可以通过使用与 Patient 模型的关系来获得你想要的结果。

$note_id = 1;

// "Pretty" syntax, but it's 3 queries
$sibling_notes = Note::find($note_id)                                      // Query 1
                      ->patient                                            // Query 2
                      ->notes()->where('id', '<>', $note_id)->pluck('id'); // Query 3

或者使用子查询

$note_id = 1;

// A bit messier, 1 query + 1 subquery
$sibling_notes = Note::where('id', '<>', $note_id)
    ->where('patient_id', function ($subquery) use ($note_id) {
        $subquery->select('patient_id')->from('notes')->where('id', $note_id)->limit(1);
    })
    ->pluck('id');

// PHP >= 7.4
Note::where('id', '<>', $note_id)
    ->where('patient_id', fn($q) => $q->select('patient_id')->from('notes')->where('id', $note_id)->limit(1))
    ->pluck('id');

以后可以变成查询作用域

# Note model
public function scopeSiblingsOf($query, $note_id)
{
    return $query->where('id', '<>', $note_id)
                 ->where('patient_id', function ($subquery) use ($note_id) {
                     $subquery->select('patient_id')
                              ->from('notes')
                              ->where('id', $note_id)
                              ->limit(1);
                 });
}

# Usage
Note::siblingsOf(1)->pluck('id');