NotesNoteCollection: the Swiss-army tool for NSF design elements

What NotesNoteCollection is

NotesNoteCollection is the LotusScript class for batch-operating on “notes”.

A “note” is the NSF’s internal storage unit — anything that gets a Note ID: data documents, forms, views, folders, agents, ACLs, profile documents, style sheets. Every one of those is a note.

So this class covers a wide surface, controlled by per-class flags:

  • Data: data documents
  • Design elements: forms, views, folders, pages, subforms, shared fields
  • Code: agents, script libraries, Java resources, action bars, the database script
  • Resources: image resources, style sheets
  • Security / config: ACL, profile documents, replication formulas
  • Misc: design indices, format elements, code elements

Its sweet spot:

“I need to batch-process some class of note in the NSF — audit every agent, DXL-export the entire design for version control, harvest every note modified in the last week.”

If you already know NotesDocumentCollection: these are different tools. NotesDocumentCollection only deals with data documents; NotesNoteCollection handles everything at the note level. There’s a full side-by-side comparison after the worked examples below.

Construction: CreateNoteCollection(Boolean)

Obtained from NotesDatabase:

Set nc = db.CreateNoteCollection(False)

That boolean controls the initial state of every Select* property:

  • True → every Select* starts as True (start with everything, then turn off what you don’t want)
  • False → every Select* starts as False (start with nothing, then turn on what you want)

False is more common in practice — you usually know which class of element you need, so you start empty and switch on the relevant flags.

32 properties — pick what you want

The full list documented in the source:

Lifecycle / general

PropertyPurpose
CountNumber of notes the collection covers
ParentThe owning NotesDatabase
LastBuildTimeWhen BuildCollection last completed
SinceTimeRestrict to notes modified after this timestamp
SelectionFormulaExtra @Formula filter on top of the Select* flags

27 Select* flags (one per note class)

BucketProperties
Data / flowSelectDocuments, SelectFolders, SelectViews
Form familySelectForms, SelectSubforms, SelectSharedFields, SelectFrameSets, SelectPages
CodeSelectAgents, SelectScriptLibraries, SelectActions, SelectDatabaseScript
ResourcesSelectImageResources, SelectJavaResources, SelectStyleSheetResources, SelectIcon
Outline / navSelectOutlines, SelectNavigators
Security / configSelectACL, SelectProfiles, SelectReplicationFormulas, SelectDataConnections
HelpSelectHelpAbout, SelectHelpUsing, SelectHelpIndex
MiscSelectMiscCodeElements, SelectMiscFormatElements, SelectMiscIndexElements

Each is a Boolean. To grab every agent and every view:

Set nc = db.CreateNoteCollection(False)
nc.SelectAgents = True
nc.SelectViews = True
Call nc.BuildCollection()

14 methods — three groups

Lifecycle

MethodPurpose
BuildCollectionWalk the database with the Select* flags + SelectionFormula and harvest the matching notes. Mandatory — without it Count = 0
ClearCollectionEmpty the collection (without resetting the Select* flags)

Set operations

MethodPurpose
Add(noteOrCollection)Add a single note or another collection
Remove(noteOrCollection)Remove from the collection
Intersect(otherCollection)Keep only notes that are in both

Bulk presets

MethodPurpose
SelectAllNotes(Boolean)Set all 27 Select* flags to True or False at once
SelectAllDataNotes(Boolean)Set just the data-related flags (SelectDocuments, etc.)
SelectAllDesignElements(Boolean)Set just the design-element flags
SelectAllAdminNotes(Boolean)Set just the admin flags (ACL, profiles, etc.)
SelectAllCodeElements(Boolean)Set just the code flags
SelectAllFormatElements(Boolean)Set just the format flags
SelectAllIndexElements(Boolean)Set just the index flags

Iteration

MethodPurpose
GetFirstNoteIDReturns the first Note ID (string form, e.g. "NT00001ABC")
GetNextNoteID(currentID)Returns the next Note ID

The documentation does not define GetLastNoteID, GetPrevNoteID, Merge, Subtract, or GetUNID — verify against the official docs when writing code.

Worked example 1: audit every agent in a database

Sub AuditAgents(db As NotesDatabase)
Dim nc As NotesNoteCollection
Dim noteID As String
Dim doc As NotesDocument
Set nc = db.CreateNoteCollection(False)
nc.SelectAgents = True
Call nc.BuildCollection()
Print "Found " & nc.Count & " agent(s)"
noteID = nc.GetFirstNoteID()
Do Until noteID = ""
Set doc = db.GetDocumentByID(noteID)
Print doc.GetItemValue("$TITLE")(0) & _
" | LastModified: " & doc.LastModified
noteID = nc.GetNextNoteID(noteID)
Loop
End Sub

Four things this snippet gets right:

  1. CreateNoteCollection(False) — start empty, turn on only what you need
  2. nc.SelectAgents = True — agents only
  3. BuildCollection() — mandatory; the collection is empty without it
  4. GetFirstNoteID / GetNextNoteID return Note ID strings, not NotesDocument objects — you fetch the document yourself with db.GetDocumentByID()

Worked example 2: list every view name (two ways compared)

A common real-world need: “get me a list of every view name in this database”. NotesNoteCollection can do it, but there’s a much shorter path:

' Method A: NotesNoteCollection
Set nc = db.CreateNoteCollection(False)
nc.SelectViews = True
Call nc.BuildCollection()
noteID = nc.GetFirstNoteID()
Do Until noteID = ""
Set doc = db.GetDocumentByID(noteID)
Print doc.GetItemValue("$TITLE")(0) ' $TITLE is "Name|Alias|Alias"
noteID = nc.GetNextNoteID(noteID)
Loop
' Method B: db.Views
ForAll v In db.Views
Print v.Name ' v.Name is the resolved primary name
' v.Aliases is the alias array
End ForAll

Trade-offs:

Method A (NotesNoteCollection)Method B (db.Views)
Just want view namesOverkill✅ The standard idiom
Pick up views + folders + agents in one pass✅ Add SelectFolders=True, SelectAgents=True❌ Three separate calls (db.Views / db.Folders / db.Agents)
Filter with SelectionFormula or SinceTime (e.g. “views modified in the last 7 days”)✅ Built in❌ Pull all, filter yourself
Feed NotesDXLExporter✅ Direct input❌ Build the collection yourself
What you actually get backNote ID strings (call GetDocumentByID separately)NotesView objects ready to use (view.AllEntries, etc.)

Picking the right one:

  • Just give me the view names” → db.Views. Three lines, done.
  • Mixed types, time/condition filtering, or DXL export pipeline” → NotesNoteCollection.

One subtle point: db.Views includes folders (a folder is a specialised view). To strictly exclude folders, filter with view.IsFolder, or use Method A with SelectViews=True only — folders have their own SelectFolders flag.

Worked example 3: pulling data documents (you can, but you usually shouldn’t)

NotesNoteCollection can harvest data documents — just turn on SelectDocuments:

Set nc = db.CreateNoteCollection(False)
nc.SelectDocuments = True ' data documents only
Call nc.BuildCollection()
noteID = nc.GetFirstNoteID()
Do Until noteID = ""
Set doc = db.GetDocumentByID(noteID)
Print doc.UniversalID & " | Form=" & doc.Form(0)
noteID = nc.GetNextNoteID(noteID)
Loop

Or use the bulk preset nc.SelectAllDataNotes(True) to flip every data-related flag at once.

But — this isn’t usually how you reach for data. Each standard idiom has a shorter path:

NeedStandard idiomWhy it beats NotesNoteCollection
All data documentsdb.AllDocumentsOne line; returns NotesDocumentCollection directly, no GetDocumentByID round-trip
Conditional queryDQL (NotesDominoQuery), then NQRP for post-processingSQL-like syntax; the engine uses indexes automatically
Formula selectiondb.Search(formula, ...)Native @Formula input
Walking a view’s entriesNotesViewNavigator or view.AllEntriesGives you the view’s own column metadata

Where NotesNoteCollection actually beats them for data

There are three situations where it wins:

  1. Mixed harvest: data + design in one pass — e.g. “every note modified in the last 7 days, including views and agents” for an audit or backup
    Call nc.SelectAllNotes(True)
    nc.SinceTime = New NotesDateTime(Now - 7)
    Call nc.BuildCollection()
  2. Feeding NotesDXLExporter — when you want data plus design exported together for version control
  3. Note IDs instead of NotesDocument objects — writing tooling or audit logs that just need the IDs

One subtlety

SelectDocuments = True does not include:

  • Deletion stubs
  • Conflict documents are handled slightly differently from NotesDocumentCollection

If you’re doing a “complete database audit” you’ll need to handle those edge cases separately.

The most common real use: DXL export

In practice, the dominant use case for NotesNoteCollection is feeding NotesDXLExporter:

Sub ExportAllDesignToDXL(db As NotesDatabase, outputPath As String)
Dim nc As NotesNoteCollection
Dim exporter As NotesDXLExporter
Dim s As New NotesSession
Dim stream As NotesStream
' 1. Collect every design element (no data documents)
Set nc = db.CreateNoteCollection(False)
Call nc.SelectAllDesignElements(True)
Call nc.BuildCollection()
' 2. Open the output file
Set stream = s.CreateStream()
Call stream.Open(outputPath, "UTF-8")
' 3. Run the DXL exporter on the entire collection
Set exporter = s.CreateDXLExporter()
Call exporter.SetInput(nc)
Call exporter.SetOutput(stream)
Call exporter.Process()
Call stream.Close()
Print "Export complete: " & outputPath
End Sub

This is the “templating tool” pattern — exporting an entire template database’s design as XML for version control, cross-environment deployment, or backup. NotesNoteCollection + NotesDXLExporter is the canonical path.

Advanced: full side-by-side with NotesDocumentCollection

If you already know NotesDocumentCollection, this table maps the differences at a glance:

NotesDocumentCollectionNotesNoteCollection
ScopeData documents onlyEvery note (design + data)
Element typeAlways NotesDocumentNote ID strings (look the document up yourself)
Constructiondb.AllDocuments, view.AllEntries.GetAllDocuments, etc.Only db.CreateNoteCollection(Boolean)
FilteringDone at the source (view, folder, query)Select* flags + SelectionFormula
Set operationsAdd doesn’t surface the original doc you addedAdd / Remove / Intersect are first-class
Best forWalking data, searching, batch updatesDesign audits, DXL export, deployment tooling

When not to use NotesNoteCollection

  • Plain batch ops on data documents → NotesDocumentCollection or DQL (NotesDominoQuery)
  • Walking a view with entry-level metadata → NotesViewNavigator
  • Just need a list of design elements → NotesDatabase.GetView() / GetForm() / GetAgent() are simpler

The sweet spot is “I need to batch-process notes at the design level”. For that scenario, there’s no better tool.

Sources

← Back to all posts