Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP] beste manier insert or update i.c.m. Laravel 4.x

Pagina: 1
Acties:

  • Donderpoes
  • Registratie: April 2011
  • Laatst online: 11-05 23:09
Beste mensen,

Ik zit even met een vraagje. Ik moet een xml importeren bestaande uit zo'n 30.000 elementen, deze moeten allemaal de database in. XML wordt dagelijks ingelezen.
Helaas is het niet mogelijk om dagelijks alleen nieuwe en/of gewijzigde elementen te ontvangen, ik moet dus altijd het volledige bestand inlezen. Ook wordt er in de XML niet bijgehouden of er een element gemuteerd is sinds de laatste export van het bestand.

Wanneer ik een nieuw Eloquent model aanmaak, in dit geval Chapter, deze een id geef en dan save() aanroep krijg ik een error betreffende duplicate key. Helaas is er nu geen ondersteuning om dan automatisch een update uit te voeren.

In mijn ogen zijn er drie manieren om dit te ondervangen.

Ik zou eerst kunnen kijken of ik het model aan kan maken vanuit de database gegevens en dan kijken of het Object niet null is. Indien null een nieuwe aanmaken. Vb:
PHP:
1
2
3
4
5
6
7
8
9
$chapter = Chapter::find($chapterElement->attributes()->id);
if ($chapter === null) {
   $chapter = new Chapter();
}
$chapter->id = $chapterElement->attributes()->id;
$chapter->structureOrder = $chapterElement->attributes()->structureorder;
$chapter->description = $chapterElement->descriptions->description[0];
$chapter->descriptionClean = Str::slug(Patchwork\Utf8::utf8_encode($chapterElement->descriptions->description[0]));
$chapter->save();

Deze manier lijkt mij te database intensief?


De manier waarop ik het nu heb is een nieuw chapter aanmaken, de save() methode in een try catch blok. Indien er een exception optreed het Object aanmaken vanuit de database en dan save() aanroepen. Vb:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$doc = new DOMDocument();
$doc->load($this->location . $this->file);
$xml = simplexml_import_dom($doc);
foreach($xml->chapter as $chapterElement) {      
   $chapter = new Chapter();
   $chapter->id = $chapterElement->attributes()->id;
   $chapter->structureOrder = $chapterElement->attributes()->structureorder;
   $chapter->description = $chapterElement->descriptions->description[0];
   $chapter->descriptionClean = Str::slug(Patchwork\Utf8::utf8_encode($chapterElement->descriptions->description[0]));
   try {
      $chapter->save();
   } catch(Exception $e) {
      $chapter = Chapter::find($chapterElement->attributes()->id);
      if ($chapter !== null) {
         $chapter->id = $chapterElement->attributes()->id;
         $chapter->structureOrder = $chapterElement->attributes()->structureorder;
         $chapter->description = $chapterElement->descriptions->description[0];
         $chapter->descriptionClean = Str::slug(Patchwork\Utf8::utf8_encode($chapterElement->descriptions->description[0]));
         $chapter->save();
      }
   }
}


De derde manier is gewoon raw sql gebruiken.
code:
1
INSERT INTO table SET id = key, foo = bar ON DUPLICATE KEY UPDATE foo = bar

Ik ben juist een framework gaan gebruiken om dit soort zaken te vereenvoudigen, dus manier drie heeft niet mijn voorkeur.
Maar kwa performance lijkt mij dit wel de betere manier, of vergis ik mij hier?

Zijn er wellicht nog andere en betere mogelijkheden?

Een klein tweede vraagje, het XML bestand wat ik importeer is zo'n 60MB, zou het beter zijn om deze met bijvoorbeeld Python in te lezen?

[ Voor 0% gewijzigd door Donderpoes op 04-10-2013 09:55 . Reden: Foutje in code ]


  • Exception
  • Registratie: Augustus 2006
  • Laatst online: 07:10
In frameworks gebruik ik altijd jouw eerste methode, echter is de laatste waarschijnlijk sneller. Een framework is niet slim genoeg om zo'n contstructie te bedenken (laatste) is mijn ervaring dus ik zou het op de eerste houden. Mocht je echt een high-traffic website bouwen, dan zou ik gaan voor een custom query (laatste).

[ Voor 17% gewijzigd door Exception op 04-10-2013 09:18 ]


  • Donderpoes
  • Registratie: April 2011
  • Laatst online: 11-05 23:09
Het zal naar alle waarschijnlijkheid geen echte high traffic website worden en het moment waarop de import gedraaid wordt is een moment waarop er geen tot heel weinig bezoekers zijn. Hij komt te draaien op een dedicated server, waarop ook wat andere kleine dingen draaien, maar die zijn ook niet druk bezocht op die tijden.

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:09
Ik ga ook altijd voor de eerste. Denk er wel aan om het query log uit te zetten ivm. performance.
code:
1
DB::connection()->disableQueryLog();

Wat betreft of het beter is om in Python te doen, ik zou het niet weten, maar is de performance niet voldoende? Ik zou het gewoon eerst proberen in php iig.

  • Donderpoes
  • Registratie: April 2011
  • Laatst online: 11-05 23:09
Goede tip, niet aan gedacht zelf.

De performance is prima, vroeg mijzelf af of een andere taal mogelijk beter is. Geen echte ervaring met dit soort imports. Meestal zijn het wat csv bestandjes die net de 1MB aantikken die ik moet importeren.

  • NickM89
  • Registratie: November 2007
  • Laatst online: 13-12-2024
Wanneer je key als primary staat & auto increment kan je niet met de hand je ID aangeven.
Check je model of je $primaryKey bestaat en zo niet zet deze dan.

  • Donderpoes
  • Registratie: April 2011
  • Laatst online: 11-05 23:09
id is mijn primary key, maar is geen auto increment.

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:09
Sinds eergisteren heb je trouwens ook firstOrNew($attributes), maar dat doet hetzelfde als je eerste optie, behalve dat hij dan ook het model vult met de attributen al.

https://github.com/larave...e/Eloquent/Model.php#L404
PHP:
1
2
3
4
5
$chapter = Chapter::firstOrNew(array('id'=>$chapterElement->attributes()->id));
$chapter->structureOrder = $chapterElement->attributes()->structureorder; 
$chapter->description = $chapterElement->descriptions->description[0]; 
$chapter->descriptionClean = Str::slug(Patchwork\Utf8::utf8_encode($chapterElement->descriptions->description[0])); 
$chapter->save();

Moet je alleen wel opletten dat id fillable is of vantevoren Chapter::unguard() aanroepen

  • Donderpoes
  • Registratie: April 2011
  • Laatst online: 11-05 23:09
Heb laravel geupdate, zal deze methode gaan gebruiken. Ziet er net wat georganiseerder uit.
Pagina: 1