web-dev-qa-db-fra.com

sauvegarde rapide d'une valeur de champ unique

J'ai environ 70 000 nœuds de type spécifié sur mon site. Je dois exécuter une mise à jour sur eux. Certaines opérations et la définition d'un champ à la valeur souhaitée. node_save est vraiment lent et provoque des plantages (pile d'appel trop longue peut-être). Existe-t-il un moyen plus rapide d'écrire des informations sur ce domaine particulier?

Il y avait field_attach_update mentionné dans un article, mais ce n'est pas beaucoup plus rapide.

EDIT: Il existe une vue assez complexe construite sur ce type de nœud, mais ne fonctionne pas sur ce champ que je souhaite mettre à jour.

19
Eloar

Je choisirais certainement field_attach_update .

L'idée est simple. Chargez simplement le nœud et enregistrez-le à l'aide de 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));

Cela ne changera aucun horodatage ni aucun autre hook que node_save invoque habituellement. Le chargement du nœud invoquera également certains crochets, donc ce n'est probablement pas si efficace.

Si vous avez le nid et si la structure du nœud est simple, vous pouvez également le faire comme ceci:

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

Quoi qu'il en soit, si vous essayez de mettre à jour autre chose que des champs, cela ne fonctionnera pas (statut de commentaire, statut publié, etc.). De plus, si vous utilisez node_save, le cache pour le nœud particulier sera effacé automatiquement pour différentes méthodes, nous devons l'effacer avec 'entity_get_controller'.

Mise à jour: Il semble que vous devriez également appeler field_attach_presave() pour permettre aux autres modules de traiter correctement l'entrée de champ. Le module de fichiers, par exemple, l'utilise pour définir l'état du fichier sur permanent à l'aide de ce hook. J'ai mis à jour mes 2 exemples ci-dessus.

30
AyeshK

Après avoir essayé toutes les approches mentionnées dans les autres réponses, j'ai eu des temps de mise à jour très lents (environ 7 jours pour 700.000 nœuds d'un type de nœud avec plus de 20 champs) jusqu'à ce que je trouve cet article: http: //www.drupalonwindows. com/fr/blog/only-update-changed-fields-or-properties-entity-drupal .

Après avoir implémenté quelque chose comme le code ci-dessous dans un hook_update, j'ai réduit le temps de mise à jour à 2 heures, ce qui, je pense, est gérable.

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

Je suggère field_attach_update aussi, et pas une requête SQL directe, car sql ne met pas à jour l'objet de cache de noeud, et dans votre prochain node_load vous ne chargez pas la valeur de champ mise à jour, vous chargez l'ancienne valeur

field_attach_update est bien meilleur qu'une requête SQL directe.

2
pico34

Si vous ne souhaitez pas enregistrer les données de champ sans provoquer les événements et actions standard, vous pouvez utiliser drupal_write_record .

Voici un exemple pour insérer Hello World dans le champ de corps d'un noeud de type article avec un id de 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);

Si votre site est multilingue, vous voudrez utiliser 'en' ou la langue de votre contenu au lieu de 'und'.

Si vous effectuez une révision, vous devrez faire attention d'insérer le bon ID de révision, sinon vous pouvez simplement insérer la même valeur que entity_id.

Notez comment ces données sont insérées dans deux tables field_data_ * et field_revision_ *. Vous devez insérer dans les deux pour vous assurer que le site fonctionne comme vous le souhaitez.

Après avoir exécuté cela, vous devrez ensuite vider les caches pour que les champs s'affichent en fonction de la configuration de votre mise en cache.

2
Thomas4019

Pour une simple mise à jour comme celle-ci où de nombreux nœuds doivent être mis à jour, j'utilise toujours une instruction de mise à jour MySQL. Oui, la mise en cache doit être prise en considération, mais vous pouvez simplement vider le cache après avoir terminé et tout va bien. Bien sûr, vous devez être familier avec la structure des données, mais elle est relativement simple en Drupal 6. (bien que horrible en Drupal 7)

2
Troy Frech

J'avais même la même exigence de mettre à jour un champ pour tous les nœuds d'un type de contenu particulier. J'ai utilisé node_load_multiple et 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);
}

Je l'ai couru à travers le drush et c'était assez rapide.

1
Suresh R

Avez-vous envisagé de faire ces mises à jour directement dans la base de données en utilisant mySQL? C'est probablement le moyen le plus simple et le plus rapide pour réaliser ce que vous voulez.

Voici un exemple simple. Vous pouvez exécuter une telle commande à partir de l'onglet 'SQL' de phpMyAdmin. Imaginez que vous ayez un type de contenu appelé Profil de membre. Vous y trouverez un champ nommé `` Type de membre '' (par exemple, entreprise, individu, organisation). Supposons que vous souhaitiez mettre à jour toutes les occurrences de "COMPANY" vers "company". La commande suivante fera exactement cela.

UPDATE content_type_member_profile SET field_type_of_member_value = 'entreprise' OERE field_type_of_member_value = 'ENTREPRISE';

Aussi, passez à la caisse Premiers pas avec MySQL

0
Bisonbleu