it-swarm.com.de

schnell speichernder Einzelfeldwert

Ich habe ungefähr 70.000 Knoten des angegebenen Typs auf meiner Site. Ich muss ein Update für sie ausführen. Einige Operationen und Einstellen eines Feldes auf den gewünschten Wert. node_save ist sehr langsam und verursacht Abstürze (möglicherweise zu langer Callstack). Gibt es eine schnellere Möglichkeit, Informationen zu diesem bestimmten Feld zu schreiben?

Dort war field_attach_update in einem Beitrag erwähnt, aber es ist nicht viel schneller.

BEARBEITEN: Auf diesem Knotentyp ist eine recht komplexe Ansicht aufgebaut, die jedoch in diesem Feld, das ich aktualisieren möchte, nicht funktioniert.

19
Eloar

Ich würde definitiv field_attach_update wählen.

Die Idee ist einfach. Laden Sie einfach den Knoten und speichern Sie ihn mit field_attach_update.

Ex:

$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));

Dadurch werden weder Zeitstempel noch andere Hooks geändert, die node_save normalerweise aufruft. Das Laden des Knotens ruft auch einige Hooks auf, so dass es wahrscheinlich nicht so effizient ist.

Wenn Sie die NID haben und die Knotenstruktur absolut einfach ist, können Sie dies auch folgendermaßen tun:

 $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_presave('node', $node);
 field_attach_update('node', $node);
  // Clear the static loading cache.
 entity_get_controller('node')->resetCache(array($node->nid));

Wenn Sie jedoch versuchen, etwas anderes als Felder zu aktualisieren, funktioniert dies nicht (Kommentarstatus, veröffentlichter Status usw.). Wenn Sie node_save verwenden, wird der Cache für den jeweiligen Knoten automatisch für verschiedene Methoden gelöscht, die wir zum Löschen mit 'entity_get_controller' benötigen.

Update: Es scheint, dass Sie auch field_attach_presave() aufrufen sollten, damit andere Module die Feldeingabe ordnungsgemäß verarbeiten können. Das Dateimodul verwendet es beispielsweise, um den Dateistatus mithilfe dieses Hooks auf permanent zu setzen. Ich habe meine 2 obigen Beispiele aktualisiert.

30
AyeshK

Nachdem ich alle in den anderen Antworten erwähnten Ansätze ausprobiert hatte, erhielt ich sehr langsame Aktualisierungszeiten (ungefähr 7 Tage für 700.000 Knoten eines Knotentyps mit mehr als 20 Feldern), bis ich diesen Artikel fand: http: //www.drupalonwindows. com/de/blog/only-update-geänderte-Felder-oder-Eigenschaften-Entität-Drupal .

Nachdem ich so etwas wie den folgenden Code in einem hook_update implementiert hatte, reduzierte ich die Aktualisierungszeit auf 2 Stunden, was ich für überschaubar halte.

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

Ich schlage vor field_attach_update auch und keine direkte SQL-Abfrage, da SQL das Knoten-Cache-Objekt nicht aktualisiert, und in Ihrem nächsten node_load Sie laden den aktualisierten Feldwert nicht, sondern den alten Wert

field_attach_update ist viel besser als eine direkte SQL-Abfrage.

2
pico34

Wenn Sie keine Felddaten speichern möchten, ohne dass die Standardereignisse und -aktionen ausgeführt werden, können Sie drupal_write_record verwenden.

Hier ist ein Beispiel zum Einfügen von Hello World in das Textfeld für einen Knoten vom Typ Artikel mit der 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);

Wenn Ihre Website mehrsprachig ist, möchten Sie "en" oder die Sprache Ihres Inhalts anstelle von "und" verwenden.

Wenn Sie eine Revision durchführen, müssen Sie darauf achten, die richtige Revisions-ID einzufügen. Andernfalls können Sie einfach denselben Wert wie die entity_id einfügen.

Beachten Sie, wie diese Daten in zwei Tabellen field_data_ * und field_revision_ * eingefügt werden. Sie sollten in beide einfügen, um sicherzustellen, dass die Site wie gewünscht funktioniert.

Nachdem Sie dies ausgeführt haben, müssen Sie die Caches löschen, damit die Felder angezeigt werden, je nachdem, wie Ihr Caching eingerichtet ist.

2
Thomas4019

Für ein einfaches Update wie dieses, bei dem viele Knoten aktualisiert werden müssen, verwende ich immer eine MySQL-Update-Anweisung. Ja, das Caching muss berücksichtigt werden, aber Sie können den Cache einfach leeren, nachdem Sie fertig sind, und alles ist gut. Sie müssen natürlich mit der Datenstruktur vertraut sein, aber sie ist relativ einfach in Drupal 6. (obwohl schrecklich in Drupal 7)).

2
Troy Frech

Ich hatte sogar die gleiche Anforderung, ein Feld für alle Knoten eines bestimmten Inhaltstyps zu aktualisieren. Ich habe node_load_multiple und field_attach_update verwendet.

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

Ich habe es durch Drush laufen lassen und es war ziemlich schnell.

1
Suresh R

Haben Sie darüber nachgedacht, diese Updates mit mySQL direkt in der Datenbank durchzuführen? Dies ist wahrscheinlich der einfachste und schnellste Weg, um das zu erreichen, was Sie wollen.

Hier ist ein einfaches Beispiel. Sie können einen solchen Befehl auf der Registerkarte 'SQL' in phpMyAdmin ausführen. Stellen Sie sich vor, Sie haben einen Inhaltstyp namens Mitgliederprofil. Darin befindet sich ein Feld mit dem Namen "Mitgliedertyp" (z. B. Firma, Person, Organisation). Angenommen, Sie möchten alle Vorkommen für 'UNTERNEHMEN' auf 'Firma' aktualisieren. Der folgende Befehl wird genau das tun.

UPDATE content_type_member_profile SET field_type_of_member_value = 'Firma' WO field_type_of_member_value = 'UNTERNEHMEN';

Checkout Erste Schritte mit MySQL

0
Bisonbleu