Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 08.05.2014 20:42:06

Eloquent ORM Выборка по связи многие ко многим

Приветствую!

Есть:

class Model extends Eloquent {
	public function prototypes()
	{
		return $this->belongsToMany('Prototype');
	}

	public function scopeAnalogs()
	{
		return $query->where(??????????????);
	}

}

class Prototype extends Eloquent {
    public function models()
    {
        return $this->belongsToMany('Model');
    }
}

Требуется из Model получить все модели у которых прототипы как у текущей модели.

Пример:
М1 - П1
М1 - П2
М2 - П1
М2 - П3
М3 - П5
М4 - П2
М5 - П6

Должны получить:
М2
М4

Подскажите решение.

Не в сети

#2 08.05.2014 21:19:41

Re: Eloquent ORM Выборка по связи многие ко многим

Сложно это сделать, не видя полей, но попробую:

		return Prototype::where('prototype_id', '=', $this->prototype_id);

Не в сети

#3 08.05.2014 21:25:23

Re: Eloquent ORM Выборка по связи многие ко многим

Все сложнее связь многие ко многим, и получить надо Models

		Schema::create('prototypes', function($table)
		{
			$table->increments('id');
			$table->string('name');
			$table->timestamps();
		});


		Schema::create('models', function($table)
		{
			$table->increments('id');
			$table->string('name');
			$table->timestamps();
		});

		Schema::create('model_prototype', function($table)
		{
			$table->increments('id');
			$table->integer('prototype_id');
			$table->integer('model_id');
			$table->timestamps();
		});

Не в сети

#4 08.05.2014 21:32:52

Re: Eloquent ORM Выборка по связи многие ко многим

Как я понимаю надо получить:
Все prototype_id из model_prototype где model_id = $this->model_id
Затем все model_id из model_prototype где prototype_id в списке полученном ранее
Затем уже получить все модели model_id которых в списке полученном в предыдущем шаге.

Не в сети

#5 08.05.2014 22:16:04

Re: Eloquent ORM Выборка по связи многие ко многим

Заполняем базу тем что дано в задаче

$data = array(
	'M1' => array('P1', 'P2'),
	'M2' => array('P1', 'P3'),
	'M3' => array('P5'),
	'M4' => array('P2'),
	'M5' => array('P6')
);
foreach($data as $model => $types){
	$mObj = Model::firstOrCreate(array('name' => $model));
	$tmp = array();
	foreach($types as $type){
		$tObj = Prototype::firstOrCreate(array('name' => $type));
		$tmp[] = $tObj->id;
	}
	$mObj->prototypes()->sync($tmp);
}

Находим что нужно для записи с именем М1

$current = 'M1';
$mCurrentObj = Model::firstOrNew(array('name' =>$current));
$pCurrent = $mCurrentObj->prototypes()->get()->lists('name');
print_r($pCurrent);

$mOut = array();
if(!empty($pCurrent)){
	foreach(Prototype::whereIn('name', $pCurrent)->get() as $pObj){
		$mFind = $pObj->models()->where('model_prototype.model_id', '!=', $mCurrentObj->id)->get();
		$mOut = array_merge($mOut, $mFind->lists('name'));
	}	
	$mOut = array_unique($mOut, SORT_STRING);
}
print_r($mOut);	

Время, качество, цена - выбирай любые 2

Не в сети

#6 09.05.2014 09:20:07

Re: Eloquent ORM Выборка по связи многие ко многим

Евгений, привет! Хотелось одним запросом. Вот что с утра на свежую голову вышло:

	public function analogs()
	{
		return DB::table('models')
			->where('id', '!=', $this->id)
			->whereIn('id', function($query)
			{
				$query->select('model_id')
					->from('model_prototype')
					->whereIn('prototype_id', function($query)
					{
						$query->select('prototype_id')
							->from('model_prototype')
							->where('model_id', '=', $this->id);
					});
			})
			->get();
	}

Осталось сделать чтоб возвращало коллекцию объектов Model

Изменено flatter (09.05.2014 09:24:49)

Не в сети

#7 09.05.2014 10:26:49

Ruzarh
Откуда: СПБ
Сообщений: 27

Re: Eloquent ORM Выборка по связи многие ко многим

flatter пишет:

Хотелось одним запросом.

Вот только одно мне интересно. Я подумываю что Субд MySql. Если я прав, то я расстрою. Запрос который уходит, технически один. А вот на уровне субд он не один, их подмножество происходит. И никаких индексов по этому запросу быть не может. Так что чаще всего это не оправдано. Хотя как сказал мне один человек: "В такой запрос меньше шансов что вкрадется ошибка из-за лишнего звена (php)". Но по факту двумя запросами по индексу этот запрос в разы легче для базы.

Не в сети

#8 09.05.2014 10:35:40

Re: Eloquent ORM Выборка по связи многие ко многим

Ruzarh пишет:

Но по факту двумя запросами по индексу этот запрос в разы легче для базы.

т.е. если сделать 3 запроса:
1. Все prototype_id из model_prototype где model_id = $this->model_id
2. Все model_id из model_prototype где prototype_id в списке полученном в шаге 1
3. Все модели model_id которых в списке полученном в шаге 2

То это будет эффективнее?

Не в сети

#9 10.05.2014 10:02:17

Re: Eloquent ORM Выборка по связи многие ко многим

Ruzarh прав, два SELECT (не JOIN) в одном «запросе» это на самом деле два запроса с небольшими оговорками, так что лучше разделить их, код будет понятней, да и отладить проще.

Но не обязательно делать 3 запроса, хватит и двух — сначала получить все прототипы текущей модели, с которыми далее нужно искать другие модели (= $protoIDs). Затем второй запрос:

sqlSELECT m.* FROM models m JOIN model_prototypes mp ON mp.prototype_id IN $protoIDs AND m.id = mp.model_id

Не в сети

Подвал раздела