it-swarm-eu.dev

rychlé ukládání hodnoty jednoho pole

Na svém webu mám asi 70 000 uzlů zadaného typu. Musím na nich spustit aktualizaci. Některé operace a nastavení jednoho pole na požadovanou hodnotu. node_save je opravdu pomalý a způsobuje zhroucení (příliš dlouhý callstack mayby). Existuje rychlejší způsob, jak psát informace o tomto konkrétním poli?

Zde bylo field_attach_update uvedeno v jednom příspěvku, ale není o moc rychlejší.

ÚPRAVA: Na tomto typu uzlů je poměrně složité zobrazení, ale v tomto poli nefunguje, které chci aktualizovat.

19
Eloar

Rozhodně bych šel na field_attach_update .

Myšlenka je jednoduchá. Jednoduše načtěte uzel a uložte jej pomocí field_attach_update.

Příklad:

$node = node_load($nid);
$node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
field_attach_presave('node', $node);
field_attach_update('node', $node);
  // Clear the static loading cache.
entity_get_controller('node')->resetCache(array($node->nid));

Tím se nezmění žádné časové razítko ani žádný jiný háček, který node_save obvykle vyvolá. Načítání uzlu také vyvolá některé háčky, takže to pravděpodobně není tak efektivní.

Pokud máte uzel a struktura uzlů je mrtvá jednoduchá, můžete to udělat také takto:

 $node = new stdClass();
 $node->nid = $nid; // Enter the nid taken. Make sure it exists. 
 $node->type = 'article';
 $node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
 field_attach_update('node', $node);
 field_attach_presave('node', $node);
  // Clear the static loading cache.
 entity_get_controller('node')->resetCache(array($node->nid));

Pokud se však pokoušíte aktualizovat něco jiného než pole, nebude to fungovat (stav komentáře, zveřejněný stav atd.). Také pokud používáte node_save, cache pro konkrétní uzel bude automaticky vymazána pro různé metody, které musíme vymazat pomocí 'entity_get_controller'.

Aktualizace: Zdá se, že byste také měli zavolat field_attach_presave(), aby ostatní moduly mohly správně zpracovat vstup pole. Souborový modul jej například používá k nastavení stavu souboru na trvalé pomocí tohoto zavěšení. Aktualizoval jsem své 2 příklady výše.

30
AyeshK

Po vyzkoušení všech přístupů uvedených v ostatních odpovědích jsem získal velmi pomalé časy aktualizace (asi 7 dní pro 700 000 uzlů typu uzlů s 20+ poli), dokud jsem nenašel tento článek: http: //www.drupalonwindows. com/en/blog/only-update-změnil-pole-or-properties-entity-drupal .

Po implementaci něco jako níže uvedený kód v hook_update jsem zkrátil čas aktualizace na 2 hodiny, což je podle mě zvládnutelné.

if (!isset($sandbox['storage']['nids'])) {
    $sandbox['storage']['nids'] = [];
    $query = 'SELECT {nid} FROM node WHERE type = \'article\';';
    $result = db_query($query)->fetchCol();
    if ($result) {
      $sandbox['storage']['nids'] = $result;
      $sandbox['storage']['total'] = count($sandbox['storage']['nids']);
      $sandbox['storage']['last_run_time'] = time();
      $sandbox['progress'] = 0;
    }
  }

  $amount = 300;
  $nids = array_slice($sandbox['storage']['nids'], 0, $amount);

  if (!empty($nids)) {
    $nodes = node_load_multiple($nids, [], TRUE);
    foreach ($nodes as $node) {
      // Lets manipualte the entity.
      $article_wrapper = UtilsEntity::entity_metadata_wrapper('node', $node);
      // Eventual logic here.

        // Field to update
        $article_wrapper->my_field = 'my_value';
        $article_wrapper->save();

    $sandbox['progress']++;
    }
    $sandbox['message'] = 'Runs left: ' . (($sandbox['storage']['total'] - $sandbox['progress'])/$amount) . ' Progress: ' . (($sandbox['progress'] * $amount)/$sandbox['storage']['total']) . '%';
    $sandbox['storage']['last_run_time'] = time();
    unset($nids);
  }
  $sandbox['storage']['nids'] = array_slice($sandbox['storage']['nids'], 100, count($sandbox['storage']['nids']));
  if (!empty($sandbox['storage']['total'])) {
    $sandbox['#finished'] = ($sandbox['storage']['total'] - count($sandbox['storage']['nids'])) / $sandbox['storage']['total'];
  }
  return $sandbox['message'];
2
dasj19

Navrhuji field_attach_update a ne přímý dotaz SQL, protože sql neaktualizuje objekt mezipaměti uzlů a ve vašem dalším node_load nebudete načítat aktualizovanou hodnotu pole, načtete starou hodnotu

field_attach_update je mnohem lepší než přímý dotaz SQL.

2
pico34

Pokud nechcete ukládat data pole, aniž by došlo ke standardním událostem a akci, můžete použít drupal_write_record .

Zde je příklad, jak vložit Hello World do pole těla pro uzel typového článku s id 1.

$values = array(
  'entity_type' => 'node',
  'bundle' => 'article',
  'entity_id' => 1,
  'revision_id' => 1,
  'language' => 'und',
  'delta' => 0,
  'body_value' => 'HELLO WORLD',
  'body_summary' => '',
  'body_format' => 'filtered_html',
);
drupal_write_record('field_data_body', $values);
drupal_write_record('field_revision_body', $values);

Pokud je váš web vícejazyčný, budete chtít místo 'und' použít 'en' nebo jazyk vašeho obsahu.

Pokud provádíte revizi, musíte být opatrní, abyste vložili správné revizní id, jinak můžete jednoduše vložit stejnou hodnotu jako entita entity_id.

Všimněte si, jak jsou tato data vložena do dvou tabulek field_data_ * a field_revision_ *. Měli byste je vložit do obou, abyste se ujistili, že web funguje podle potřeby.

Po spuštění budete muset vyčistit mezipaměti pro pole, která se zobrazí, v závislosti na nastavení vašeho ukládání do mezipaměti.

2
Thomas4019

Pro takovou jednoduchou aktualizaci, kdy je třeba aktualizovat mnoho uzlů, vždy používám aktualizační příkaz MySQL. Ano, ukládání do mezipaměti je třeba vzít v úvahu, ale po dokončení můžete mezipaměť propláchnout a je to všechno dobré. Musíte samozřejmě znát strukturu dat, ale je to relativně jednoduché v Drupal 6. (i když v Drupal 7) hrozné)

2
Troy Frech

Dokonce jsem měl stejný požadavek na aktualizaci pole pro všechny uzly určitého typu obsahu. Použil jsem node_load_multiple a field_attach_update .

$nodes = node_load_multiple(array(), array('type' => 'content_type_name'));
foreach ($nodes as $node) {
  $node->field_name['und'][0]['value'] = 'field value';
  field_attach_update('node', $node);
}

Projel jsem to drushem a bylo to docela rychlé.

1
Suresh R

Uvažovali jste o provedení těchto aktualizací přímo do databáze pomocí mySQL? Je to pravděpodobně nejjednodušší a nejrychlejší způsob, jak dosáhnout toho, co chcete.

Zde je jednoduchý příklad. Takový příkaz můžete spustit na záložce 'SQL' v phpMyAdmin. Představte si, že máte typ obsahu s názvem Profil člena. V něm je pole s názvem „Typ člena“ (např. Společnost, jednotlivec, organizace). Řekněme, že chcete aktualizovat všechny výskyty pro „SPOLEČNOST“ na „společnost“. Následující příkaz provede právě to.

UPDATE content_type_member_profile SET field_type_of_member_value = 'company' WHERE field_type_of_member_value = 'SPOLEČNOST';

Rovněž pokladna Začínáme s MySQL

0
Bisonbleu