Retrieving part of the bookmarks tree

This document provides a quick start for those wishing to quickly retrieve a portion of the bookmarks tree. Bookmarks are retrieved using the Places query system.

For more basic bookmarks examples, see Manipulating bookmarks using Places.

Get the query and options objects

All querying is done through the history service. First, you need to get an empty query and options objects from the history service:

var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"]
                               .getService(Components.interfaces.nsINavHistoryService);
var options = historyService.getNewQueryOptions();
var query = historyService.getNewQuery();

Find the folder you want to get

Known folder IDs are retrieved from the bookmarks service. Attributes defined in /toolkit/components/places/public/nsINavBookmarksService.idl are: bookmarksMenuFolder, tagsFolder, unfiledBookmarksFolder and toolbarFolder. You can also get folder IDs from a previous query.

This example will get the ID of the bookmarks toolbar:

var bookmarksService = Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
                                 .getService(Components.interfaces.nsINavBookmarksService);
var toolbarFolder = bookmarksService.toolbarFolder;

The placesRoot is the root folder in the whole Places hierarchy. It contains administrative data as well as user data, and is therefore not recommended for use in querying.

Configure the query

To get a hierarchical bookmarks result, pass the folder ID to setFolders in your query object:

query.setFolders([toolbarFolder], 1);

Run the query

The executeQuery and executeQueries functions will return an nsINavHistoryResult object containing the results of your query:

var result = historyService.executeQuery(query, options);

Get the results

When you are querying for exactly one folder grouped by folder with no fancy query parameters such as keywords or date ranges (as in this example), the root of the result will be an nsINavHistoryContainerResultNode corresponding to your folder. If you have a complex query the root will be a nsINavHistoryQueryResultNode.

Before accessing the children of any result container, you must first open it, and then you can iterate the children. As long as the container is open, it will listen for notifications from the bookmarks system to keep itself up-to-date. When you're done, be sure to close the container to free up the resources. Otherwise, it will continue to get observer notifications and update itself, slowing down the whole browser.

var rootNode = result.root;
rootNode.containerOpen = true;

// iterate over the immediate children of this folder and dump to console
for (var i = 0; i < rootNode.childCount; i ++) {
  var node = rootNode.getChild(i);
  dump("Child: " + node.title + "\n");
}

// close a container after using it!
rootNode.containerOpen = false;

If you encounter a node with a type of RESULT_TYPE_FOLDER or another type of container, you can open these folders and descend into the hierarchy. You will want to read the section "Using the results" in Places:Query System to understand the different result types.

Complete code listing

var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"]
                               .getService(Components.interfaces.nsINavHistoryService);
var options = historyService.getNewQueryOptions();
var query = historyService.getNewQuery();

var bookmarksService = Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
                                 .getService(Components.interfaces.nsINavBookmarksService);
var toolbarFolder = bookmarksService.toolbarFolder;

query.setFolders([toolbarFolder], 1);

var result = historyService.executeQuery(query, options);
var rootNode = result.root;
rootNode.containerOpen = true;

// iterate over the immediate children of this folder and dump to console
for (var i = 0; i < rootNode.childCount; i ++) {
  var node = rootNode.getChild(i);
  dump("Child: " + node.title + "\n");
}

// close a container after using it!
rootNode.containerOpen = false;