단일 필드 값을 빠르게 저장


19

내 사이트에 약 70k 개의 지정된 유형의 노드가 있습니다. 그들에 대한 업데이트를 실행해야합니다. 일부 작업 및 하나의 필드를 원하는 값으로 설정 node_save실제로 느리고 충돌이 발생합니다 (너무 긴 호출 스택 mayby). 이 특정 필드에 정보를 작성하는 더 빠른 방법이 있습니까?

field_attach_update한 게시물 에 언급되었지만 훨씬 빠르지는 않습니다.

편집 :이 노드 유형에 대해 상당히 복잡한보기가 있지만 업데이트하려는이 필드에서 작동하지 않습니다.

답변:


30

나는 확실히 갈 것이다 field_attach_update.

아이디어는 간단하다. 노드를로드하고 field_attach_update를 사용하여 저장하십시오.

전의:

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

이것은 node_save가 일반적으로 호출하는 타임 스탬프 또는 다른 후크를 변경하지 않습니다. 노드를로드하면 일부 후크가 호출되므로 그렇게 효율적이지 않을 수 있습니다.

nid가 있고 노드 구조가 단순하지 않은 경우 다음과 같이 수행 할 수 있습니다.

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

어쨌든 필드 이외의 다른 것을 업데이트하려고하면 작동하지 않습니다 (댓글 상태, 게시 상태 등). 또한 node_save를 사용하는 경우 특정 방법에 대한 캐시는 다른 방법으로 자동으로 지워지며 'entity_get_controller'로 지워야합니다.

업데이트 :field_attach_presave() 다른 모듈이 필드 입력을 올바르게 처리하도록 호출해야합니다 . 예를 들어 파일 모듈은이 후크를 사용하여 파일 상태를 영구로 설정하는 데 사용합니다. 위의 두 가지 예를 업데이트했습니다.


나는 nid를 가지고 있지만 노드의 구조는 그렇게 간단하지 않지만 업데이트하려는 필드는 매우 간단합니다. 기존 노드에 대해 하나의 필드 만 설정하고 (nid로 식별되었지만로드되지 않음) 전화를 걸면 무엇을 기대할 수 field_attach_update있습니까?
Eloar

4
엔터티 쿼리를 사용하여 결과가 느려졌습니다. 에서 전환 그래서 node_savefield_attach_update와에서 EntityFieldQuerydb_query_range확실히 보답했다. 3 시간 업데이트에서 40 분
Eloar

2

표준 이벤트 및 조치가 발생하지 않고 필드 데이터를 저장하지 않으려면 drupal_write_record 를 사용할 수 있습니다 .

다음은 id가 1 인 article 유형의 노드에 대한 본문 필드에 Hello World를 삽입하는 예입니다.

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

사이트가 다국어 인 경우 'und'대신 'en'또는 콘텐츠 언어를 사용하려고합니다.

개정을 수행하는 경우 올바른 개정 ID를 삽입해야합니다. 그렇지 않으면 entity_id와 동일한 값을 삽입 할 수 있습니다.

이 데이터가 field_data_ * 및 field_revision_ * 두 테이블에 어떻게 삽입되는지 참고하십시오. 사이트가 원하는대로 작동하도록하려면 둘 다에 삽입해야합니다.

이를 실행 한 후 캐싱 설정 방법에 따라 필드가 표시되도록 캐시를 지워야합니다.


2

많은 노드를 업데이트해야 할 경우 이와 같은 간단한 업데이트를 위해 항상 MySQL 업데이트 문을 사용합니다. 그렇습니다. 캐싱을 고려해야하지만 완료 후에 캐시를 플러시하면됩니다. 물론 데이터 구조에 익숙해야하지만 Drupal 6에서는 비교적 간단합니다 (Drupal 7에서는 끔찍하지만).


프로젝트는 Drupal 7을 위해 만들어졌습니다. 모듈의 모든 부분이 Drupal DB 구조에서 직접 조작되어 값을 읽고 SQL 쿼리가 EntityFieldQueries보다 훨씬 빠르기 때문에 검색되었습니다.
Eloar

2

field_attach_updateSQL은 노드 캐시 객체를 업데이트하지 않기 때문에 직접 SQL 쿼리가 아니라도 제안 합니다. 다음 node_load에 업데이트 된 필드 값을로드하지 않으면 이전 값을로드합니다.

field_attach_update 직접 SQL 쿼리보다 훨씬 낫습니다.


Ayesh K는 stdClass로드하지 않고 객체로 노드를 생성 할 것을 제안했습니다 . 모든 필드를 설정하지 않고이 방법으로 노드를 업데이트하려고하면 어떤 일이 발생할 수 있는지 알고 있습니까? 그것들을 널이나 기본값으로 덮어 쓸 것인가? Mayby는 프로세스를 업데이트하여 무시됩니까?
Eloar

1
Ayeshs 메소드 (새로운 stdClass 등 ...)로 노드를 직접 저장할 수 있습니다. UI 만 필요한 필드를 검증합니다
pico34

모든 필드를 설정하지 않고이 방법으로 노드를 업데이트하고 어떤 일이 발생하는지 확인하려고합니다. 모듈 업데이트 절차 (배치)에서 노드를 업데이트하는 가장 빠른 방법 일 수 있습니다.
Eloar

2

다른 답변에 언급 된 모든 접근 방식을 시도한 결과이 기사를 찾을 때까지 업데이트 시간이 매우 느 렸습니다 (20+ 필드가있는 노드 유형의 700.000 노드의 경우 약 7 일) : http://www.drupalonwindows.com/en/ blog / only-update-changed-fields-or-properties-entity-drupal .

hook_update에서 아래 코드와 같은 것을 구현 한 후 업데이트 시간을 2 시간으로 줄였습니다.

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'];

1

특정 콘텐츠 유형의 모든 노드에 대해 필드를 업데이트해야하는 동일한 요구 사항도있었습니다. node_load_multiplefield_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);
}

나는 돌진을 통해 그것을 실행하고 꽤 빠르다.


0

mySQL을 사용하여 데이터베이스로 직접 이러한 업데이트를 수행하는 것을 고려 했습니까? 아마도 원하는 것을 달성하는 가장 간단하고 빠른 방법 일 것입니다.

다음은 간단한 예입니다. phpMyAdmin의 'SQL'탭에서 이러한 명령을 실행할 수 있습니다. 멤버 프로파일이라는 컨텐츠 유형이 있다고 가정하십시오. 여기에는 '회원 유형'(예 : 회사, 개인, 조직)이라는 이름의 필드가 있습니다. '회사'에 대한 모든 항목을 '회사'로 업데이트하려고한다고 가정합니다. 다음 명령은 바로 그렇게 할 것입니다.

content_type_member_profile 업데이트 SET field_type_of_member_value= 'company'WHERE field_type_of_member_value= '회사';

또한 Checkout MySQL 시작하기


옵션 중 하나입니다. 확인하고 구현하기 위해 마지막으로 남겨 둡니다. 나는 drupal 구조와 결함을 많이 망치고 싶지 않습니다. 먼저 Drupal API를 통해 직접 솔루션을 찾습니다. 몇 가지 예를 제공 할 수 있다면 대단히 감사하겠습니다.
Eloar

Goog point. 초기 답변에 간단한 예를 추가했습니다.
Bisonbleu

어, 나는 테이블의 모든 레코드를 업데이트 할만 큼 SQL을 잘 알고 있습니다. 문제가 아닙니다. 문제는 drupal이 데이터 (특히 메타 데이터)를 저장하는 방식에 익숙하지 않다는 것입니다. 이러한 시스템에는 항상 많은 캐싱, 보존 등이 있으므로 가장 낮은 수준에서 업데이트하면 일부 결함이 발생할 수 있습니다. 그래서이 문제가 발생하면 가장 낮은 수준에서 시도하고 실제 혼란에 대비할 것입니다.
Eloar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.