#
Migration Examples
This page provides common examples of migration scripts. You can adapt these to fit your specific data model and requirements.
#
1. Updating Data
This example iterates through all Person nodes and normalizes the Email property to lowercase.
// Report indefinite progress initially
Progress.Indeterminate();
var query = Q().StartAt("Person");
var total = query.Count();
var count = 0;
// Iterate using AsTypedUIDEnumerable() for better memory management with large datasets
// This returns TypedUID128 structs which contain both the UID and the Type ID
foreach (var uid in query.AsTypedUIDEnumerable())
{
// Always check for cancellation
CancellationToken.ThrowIfCancellationRequested();
// Lock the node for update
var node = await Graph.TryGetLockedAsync(uid.UID);
if (node != null)
{
var email = node.GetString("Email");
// Check if update is needed
if (!string.IsNullOrEmpty(email) && email.Any(char.IsUpper))
{
node["Email"] = email.ToLowerInvariant();
// Commit the change
await Graph.CommitAsync(node);
}
}
count++;
// Report progress periodically
if (count % 100 == 0)
{
Progress.Set(count, total).Message($"Processed {count}/{total}");
}
}
Progress.Done();
#
2. Adding Edges Based on Data
This example creates a relationship between Ticket and Person nodes based on an email address stored in the ticket.
Progress.Indeterminate();
var query = Q().StartAt("Ticket");
var total = query.Count();
var count = 0;
foreach (var uid in query.AsTypedUIDEnumerable())
{
CancellationToken.ThrowIfCancellationRequested();
var ticketNode = await Graph.TryGetLockedAsync(uid.UID);
if (ticketNode != null)
{
var assigneeEmail = ticketNode.GetString("AssigneeEmail");
if (!string.IsNullOrEmpty(assigneeEmail))
{
// Find the corresponding Person node (read-only query)
// Note: Assuming "Email" is indexed or unique
var personNode = Q().StartAt("Person").Where("Email", assigneeEmail).FirstOrDefault();
if (personNode != null)
{
// Create a unique edge "AssignedTo" from Ticket to Person
// AddUniqueEdgeTo ensures no duplicate edges of this type to the same target
ticketNode.AddUniqueEdgeTo("AssignedTo", personNode.UID);
await Graph.CommitAsync(ticketNode);
}
}
}
count++;
if (count % 100 == 0)
{
Progress.Set(count, total).Message($"Processed {count}/{total}");
}
}
Progress.Done();
#
3. Search and Queue for Re-indexing
This example uses a similarity search to find nodes related to a specific topic and queues them for file content re-extraction. This is useful if you want to re-process specific files with updated extraction logic or OCR settings.
Progress.Indeterminate();
// Search for File nodes containing the text "contract updates"
// StartSearch uses the full-text index
var query = Q().StartSearch("File", "", Search.Parse("contract updates"));
var total = query.Count();
var count = 0;
foreach (var uid in query.AsTypedUIDEnumerable())
{
CancellationToken.ThrowIfCancellationRequested();
// Queue the file for re-indexing (content extraction)
// Accessing 'Internals' is necessary to reach the low-level IndexManager
Graph.Internals.Indexes.Enqueue(uid.Type, uid.UID);
count++;
if (count % 10 == 0)
{
Progress.Set(count, total).Message($"Queued {count}/{total}");
}
}
Progress.Done();