What is the migration syntax to narrow this array field type with an optional item
property to one where the item
property is required?
otherRevenue: Array<{
otherRevenueType: String | Null,
amount: Number,
item: String?
}>
to
otherRevenue: Array<{
otherRevenueType: String | Null,
amount: Number,
item: String
}>
Thanks @wallslide. @ptpaterson mentioned he’d already helped you in a support ticket. However, I wanted to post a workaround for anyone else following along.
Migrations don’t support object arrays
Migrating array elements isn’t supported. For example, a migration statement’s field accessors can’t reference nested fields in an object Array. As a result, you can’t fix this using a field migration.
Add a check constraint
Instead, to ensure new and updated documents contain the item
property, you can use a check constraint:
collection MyColl {
otherRevenue: Array<{
otherRevenueType: String | Null,
amount: Number,
item: String?
}>
// Ensures `item` is non-null.
check itemIsPresent(.otherRevenue.every(.item != null))
}
Update existing documents
The check constraint ensures new and updated documents have the item
property. But it doesn’t change existing documents. To update those documents, we’ll need to use an FQL query. Since this could involve a large dataset, we can use paginate()
to perform the change over several queries.
For the first query:
// Get any documents with a null (missing) `item` value.
let page = MyColl.where(.otherRevenue.any(.item == null))
.pageSize(20).paginate()
let data = page.data
// Iterate through each of the above documents.
// If null (missing), set `item` to the backfill value.
data.forEach(document => {
let updatedOtherRevenue: Any = document.otherRevenue.map(obj => {
if (obj.item == null) {
Object.assign(obj, {item: 'backfill'})
} else {
obj
}
})
document.update({otherRevenue: updatedOtherRevenue})
})
// Return the after cursor.
page {
after
}
For subsequent queries:
// Subsequent queries.
// Uses `Set.paginate()` to iterate through subsequent pages.
// Replace `hdw...` with the after cursor from the previous query.
// Repeat until the returned after cursor is null.
let page = Set.paginate("hdW...")
let data = page.data
data.forEach(document => {
let updatedOtherRevenue: Any = document.otherRevenue.map(obj => {
if (obj.item == null) {
Object.assign(obj, {item: 'backfill'})
} else {
obj
}
})
document.update({otherRevenue: updatedOtherRevenue})
})
page {
after
}
1 Like