9

I have a module that programmatically adds a whole lot of nodes to my Drupal 7 site. To prevent duplicates I want to check whether the title of my newly created node doesn't already exist in the system. There will never be a case where two nodes have the same name. I've tried using node_load(), but that doesn't seem to allow me to load nodes based on a title.

I'm stumped on how to proceed, so I was wondering if somebody here could help me.

To summarize: How do I check whether a node with a certain title already exists?

Thanks.

Adam Wenger
  • 15,846
  • 6
  • 48
  • 63
Eruonen
  • 101
  • 1
  • 1
  • 3
  • 1
    If you want we can move this to our [Drupal site](drupal.stackexchange.com) where it might get better coverage. Please flag if you'd like us to do this (but don't cross-post). Thanks. – Kev Dec 04 '11 at 14:30
  • Related: [How to load a node based on its title?](http://drupal.stackexchange.com/q/5955/1908) at DS – kenorb Jul 29 '15 at 16:15

6 Answers6

18

Node are entities, so you can use the EntityFieldQuery class to query for them. This way, you don't have to bother how the information is stored in the database. And, shall you need to add additional filters based on field values, code evolution will be easy.

$result = (new EntityFieldQuery())
  ->entityCondition('entity_type', 'node')
  ->propertyCondition('title', $title)
  ->execute();
$title_is_unique = empty($result['node']);
Pierre Buyle
  • 4,792
  • 2
  • 30
  • 31
  • That's an awful lot of overhead for such a simple query, field storage doesn't extend to entity properties so using EntityFieldQuery here has no real benefit – Clive Dec 04 '11 at 12:31
  • 2
    Yep, there is some overhead using EntityFieldQuery to query a single node property. But since it will only apply to a multi-nodes creation process, there is a good chance that the performance cost will be marginal. And it will be easier to maintain should the node creation process evolve into something that should check for several conditions. – Pierre Buyle Dec 04 '11 at 16:24
  • If you use Entity translation and the Title module, the code needs to be updated to query for the title_field field instead of the title property. – Pierre Buyle Sep 24 '14 at 15:54
  • 1
    I know this is many years later, but there's a bug in this code - you can't chain a PHP constructor. In 5.4 and up you can use `(new EntityFieldQuery())->`, but as written this should give a fatal error – Clive Sep 24 '14 at 15:58
8

You could get all the node titles with a SQL query like:

 $row = db_query('SELECT nid FROM {node} WHERE title = :mytitle', array(':mytitle' => $myNewTitle))->fetchField();
 if(!isset($row['nid'])) {
    //safe to continue
 } else {
    //that title is already there and its in node with node id "nid"
 }

And if there are no results returned then you may assume you're good to go.

Or alternatively you could edit the node table to make the title field UNIQUE and handle the error thrown by MySQL. Don't really know how feasible that is though.

KerrM
  • 4,773
  • 3
  • 31
  • 58
  • +1 this is the best way to accomplish this. You should consider joining the revisions table in though to get the latest version of the data – Clive Dec 04 '11 at 12:39
  • Please, wrap your table name in curly brace when writing custom DB query. – Pierre Buyle Sep 24 '14 at 15:56
4

Here is this D7 approach utilizing the API and the count function.

$query = db_select('node', 'n')
  ->fields('n', array('nid'))
  ->condition('n.title', $myNewTitle, '=');

return $query->countQuery()->execute()->fetchField();
iLLin
  • 740
  • 3
  • 7
4
node_load_multiple(array(), array('title' => $title));

Source: The guts of DrupalWebTestCase::DrupalGetNodeByTitle

beth
  • 1,746
  • 3
  • 20
  • 37
2

Just a friendly headsup. For security you should ALWAYS use curly brackets around tables in drupal sql querys! It prevents SQL injection attacks.

so it should be: (notice {node} )

 $row = db_query('SELECT nid FROM {node} WHERE title = :mytitle', array(':mytitle' =>   $myNewTitle))->fetchField();
 if(!isset($row['nid'])) {
    //safe to continue
 } else {
    //that title is already there and its in node with node id "nid"
 }
Cristobal Wetzig
  • 381
  • 1
  • 13
  • For a node query, it seems that in order to have node access restrictions check working, you have to use a dynamic query with the 'node_access' tag, see http://drupal.org/update/modules/6/7#db_rewrite_sql. For this case, this doesn't really matter as the duplicate title detection shouldn't worry about node access restrictions. But using dynamic query for nodes it is a good habit to take. – Pierre Buyle Dec 05 '11 at 07:06
  • 1
    Curly brackets are only to prefix the table if you have your prefix set in your settings file. has nothing to do with SQL Injection. I use the D7 sql API to add fields and conditions so in your example if I was to guess, your variable $myNewTitle is NOT escaped? – iLLin Mar 11 '13 at 18:29
1

The correct way is to add an UNIQUE index to the database. Then you will be sure that all titles are unique. Is easy:

db_add_unique_key("{node}", "title_uniq", array("title"));
Ilya Larin
  • 11
  • 1