I am developing a module for a trade fair ERP system that aims to create a virtual representation of a trade fair booth. The booth features various walls (left, right, back) with carpets displayed on them, as well as multiple stacks of carpets on the floor and sample stacks. The goal is to mirror the physical arrangement of carpets in a virtual setup accurately.
To achieve this, I have created the following data structures:
rugStackItem
Schema:rugRef
: A FirestoreDocumentReference
to a carpet document.positionInStack
: An integer indicating the carpet's position in its respective stack.
standSetup
Schema:leftWallStack
,rightWallStack
,backWall
: Lists that containrugStackItem
objects, representing carpets hanging on the respective walls.floorStacks
,samples
: Lists offloorStack
objects. EachfloorStack
contains a list ofrugStackItem
objects, representing the stacks of carpets on the floor.
floorStack
Schema:stackPosition
: A string indicating the stack's position (e.g., "front-left", "back-center").stackItems
: A list ofrugStackItem
objects.positionFromLeft
: An integer representing the stack's position from the left side of the floor.
The challenge arises when attempting to add or remove carpets from the floorStacks
or samples
. These actions involve updating a nested array within a floorStack
object, which Firestore does not support directly. I am experiencing the unintended consequence of the entire array being overwritten when I try to update a single element within it.
Here is a snippet of the Dart function used for adding/removing carpets:
dartCopy code
// Dart function to add or remove carpets Future<List<RugStackItemStruct>?> tradeFairAddOrRemoveRug( // function parameters ) async { // function logic // Firestore update operations }
For walls (leftWallStack
, rightWallStack
, backWall
), the add/remove functionality works flawlessly. However, for floorStacks
and samples
, which are arrays of floorStack
objects (which in turn contain arrays of rugStackItem
), the same operation fails due to Firestore's array handling limitations.
Here are my questions:
How can I perform add/remove operations within nested arrays in Firestore while maintaining the integrity of the other elements?
Are there alternative data structuring strategies that could simplify these operations within Firestore's constraints?
Has anyone faced and overcome a similar challenge with Firestore arrays, and if so, how?
Any insights, code snippets, or strategy suggestions would be incredibly helpful as I navigate this complex issue.
Thank you in advance for your time and assistance.
My schema screenshots and complete code is below
Future<List<RugStackItemStruct>?> tradeFairAddOrRemoveRug(
String stackName,
DocumentReference? rugRef,
TradeFairsRecord? tradeFairDoc,
bool isDelete,
) async {
if (rugRef == null || tradeFairDoc == null) {
print('rugRef or tradeFairDoc is null');
return null;
}
print('Operation starts...');
List<RugStackItemStruct>? targetStack;
String firestoreFieldName = '';
int stackIndex = -1;
bool isWallStack = false;
// Print initial floorStack array
print('Initial floorStack: ${tradeFairDoc.standSetup.floorStacks}');
// Check the walls first
switch (stackName) {
case 'Left Wall':
firestoreFieldName = 'leftWallStack';
targetStack = tradeFairDoc.standSetup.leftWallStack;
isWallStack = true;
break;
case 'Right Wall':
firestoreFieldName = 'rightWallStack';
targetStack = tradeFairDoc.standSetup.rightWallStack;
isWallStack = true;
break;
case 'Back Wall':
firestoreFieldName = 'backWall';
targetStack = tradeFairDoc.standSetup.backWall;
isWallStack = true;
break;
}
print('Checked wall stacks, isWallStack: $isWallStack');
// If not a wall, check floor stacks and samples
if (!isWallStack) {
for (var i = 0; i < tradeFairDoc.standSetup.floorStacks.length; i++) {
if (tradeFairDoc.standSetup.floorStacks[i].stackPosition == stackName) {
stackIndex = i;
targetStack = tradeFairDoc.standSetup.floorStacks[i].stackItems;
firestoreFieldName = 'floorStacks';
print('Found stack in floorStacks at index: $stackIndex');
break;
}
}
if (targetStack == null) {
for (var i = 0; i < tradeFairDoc.standSetup.samples.length; i++) {
if (tradeFairDoc.standSetup.samples[i].stackPosition == stackName) {
stackIndex = i;
targetStack = tradeFairDoc.standSetup.samples[i].stackItems;
firestoreFieldName = 'samples';
print('Found stack in samples at index: $stackIndex');
break;
}
}
}
}
// Check if we found a target stack
if (targetStack == null ||
firestoreFieldName.isEmpty ||
(stackIndex == -1 && !isWallStack)) {
print('Invalid stackName or unable to find the stack path: $stackName');
return null;
}
print(
'Target stack found, firestoreFieldName: $firestoreFieldName, stackIndex: $stackIndex');
String firestoreArrayPath = isWallStack
? 'standSetup.$firestoreFieldName'
: 'standSetup.$firestoreFieldName.$stackIndex.stackItems';
print('Firestore array path: $firestoreArrayPath');
// Add or delete logic
if (!isDelete) {
// Add logic
if (targetStack.any((item) => item.rugRef == rugRef)) {
print('Rug already exists in the stack, doing nothing');
return targetStack;
}
RugStackItemStruct newItem = RugStackItemStruct(
rugRef: rugRef,
positionInStack: targetStack.length + 1,
);
targetStack.add(newItem);
await tradeFairDoc.reference.update({
firestoreArrayPath: targetStack.map((item) => item.toMap()).toList(),
});
print('Firestore add successful for $stackName');
} else {
// Delete logic
int itemIndex = targetStack.indexWhere((item) => item.rugRef == rugRef);
if (itemIndex != -1) {
targetStack.removeAt(itemIndex);
// Adjust the positions in the stack
for (int i = itemIndex; i < targetStack.length; i++) {
targetStack[i].positionInStack -= 1;
}
await tradeFairDoc.reference.update({
firestoreArrayPath: targetStack.map((item) => item.toMap()).toList(),
});
print('Firestore delete successful for $stackName');
} else {
print('Rug not found in the stack, doing nothing');
}
}
// Print final floorStack array
print('Final floorStack: ${tradeFairDoc.standSetup.floorStacks}');
return targetStack;
}