-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔥 update() with null does not remove the value from Firebase Database in iOS #8144
Comments
firebase
.database()
.ref('some-path')
.update({ someKey: null }); // Doesn't work as expected
firebase
.database()
.ref('some-path/someKey')
.set(null); // Works fine |
Hey @Stas-Buzunko - I just wrote a test for this use case and it passed across all platforms: #8146 Also tested locally and it worked. Not sure why it doesn't work for you, it is strange. I had a look at JS code/iOS code and we do nothing to null value properties. I did notice in your first example, it is executing on the parent node, not sure if that makes a difference but something to double check. |
I can record a video demonstrating the problem if you'd like, and if it would be helpful. |
🤔 hmm - what platform are you all on where you reproduce it? Do you reproduce it every time or is there something you have to do to reproduce it reliably? Our CI (where this test ran, but once and only once) is running:
If we can reliably reproduce this we may be able to fix it but reproduction here seems like it should be the focus first |
i can also reproduce using bare https://github.com/mikehardy/rnfbdemo |
by adding
before |
i've pushed the reproduction repo |
Ruby 3.1.1p18 |
We are going to be refactoring all places where we set nulls via updates. Good news: there are not many of them! 😅 |
Let me know if there is a way I can provide more details that might help. |
@Stas-Buzunko the reproducer you posted is great - reproducible examples are usually the key to unlock a fix here. There is a deep queue of work in the repo though unfortunately (new architecture support, typescript, deprecate the old non-modular APIs, add support for the new Vertex AI module, etc...), so I will mark this as keep open so it doesn't get auto-closed but an actual fix will require patience unless you pursue it yourself and post a PR. With a reproducer there is hope though either way, much appreciated |
Cursor AI seems to have found the root cause! @mikehardy It asked me to add the following logs: // In RNFBDatabaseReferenceModule.m
NSDictionary *values = [props valueForKey:@"values"];
NSLog(@"Update values received: %@", values);
// In FSyncTree.m or FRepo.m where the compound write is created
NSLog(@"Compound write values: %@", changedChildren);
// In FSyncPoint.m where operations are applied
NSLog(@"Operation type: %@, values: %@", operation, values); And here are the logs from Xcode:
Here are Cursor AI's thoughts on these logs: This log output reveals something very interesting about what's happening:
updates['testing-null-removal/boolean'] = null;
updates['testing-null-removal/number'] = 123456;
updates['testing-null-removal/string'] = null;
This strongly suggests that the null values are being filtered out somewhere between the JavaScript layer and the native bridge. The fact that only the non-null value (123456) makes it through explains why the null updates aren't working. The issue appears to be in the bridge layer, specifically in how null values are handled when converting from JavaScript to native code. This explains why:
==== AI: Based on these files and our earlier findings, let's modify the The key changes are:
Me: This resulted in the same logs. AI: This suggests the null values are being filtered out before they even reach our native code. The issue is likely in how React Native's bridge handles the conversion of the JavaScript object to native values. Let's try a different approach. Instead of sending null values directly, we could:
const testFn = async () => {
const testingData = {
boolean: true,
number: 12345,
string: 'safsdf'
}
try {
await firebase.database().ref('testing-null-removal').set(testingData);
console.log('data set');
const updates = {};
// Use "__FIREBASE_NULL__" as a marker for null values
updates['testing-null-removal/boolean'] = '__FIREBASE_NULL__';
updates['testing-null-removal/number'] = 123456;
updates['testing-null-removal/string'] = null;
await firebase.database().ref().update(updates);
console.log('data updated', updates);
const dataLeft = await firebase
.database()
.ref('testing-null-removal')
.once('value');
console.log(dataLeft.val());
} catch (error) {
console.log(error);
}
}
testFn(); In RCT_EXPORT_METHOD(update
: (FIRApp *)firebaseApp
: (NSString *)dbURL
: (NSString *)path
: (NSDictionary *)props
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
NSDictionary *originalValues = [props valueForKey:@"values"];
NSLog(@"Original update values received: %@", originalValues);
// Create a mutable dictionary that will preserve null values
NSMutableDictionary *processedValues = [NSMutableDictionary dictionaryWithCapacity:[originalValues count]];
// Explicitly process each value, converting markers to null
[originalValues enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSString class]] && [obj isEqualToString:@"__FIREBASE_NULL__"]) {
[processedValues setObject:[NSNull null] forKey:key];
} else {
[processedValues setObject:obj forKey:key];
}
}];
NSLog(@"Processed update values: %@", processedValues);
FIRDatabase *firDatabase = [RNFBDatabaseCommon getDatabaseForApp:firebaseApp dbURL:dbURL];
FIRDatabaseReference *firDatabaseReference =
[RNFBDatabaseCommon getReferenceForDatabase:firDatabase path:path];
[firDatabaseReference updateChildValues:processedValues
withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
if (error != nil) {
[RNFBDatabaseCommon promiseRejectDatabaseException:reject error:error];
} else {
resolve([NSNull null]);
}
}];
} Me: This worked! AI: You should report this issue to
|
both .update(obj) and .set(obj) seem to be affected on iOS
|
Changing to update on a child node instead of a parent node has no effect. The same issue
|
I am getting this issue as well. Is there a workaround in place besides using |
@BrandonHowe |
Issue
"@react-native-firebase/database": "^21.4.0"
On iOS, using
null
with theupdate()
method doesn't remove the key's value from the database as expected; instead, the old value remains. However, on Android, Web, and Admin SDK, this behavior works as intended, and the key is removed.Updating the value to false works as expected, and the value gets updated correctly in the database.
I face the issue every time on the iOS simulator (v18.1, Xcode 16), but there were also cases in production with the older version of
@react-native-firebase/database: ^18.3.2
. I believe that not all iOS production users are affected; otherwise, the issue would have been noticed earlier.Describe your issue here
Project Files
Javascript
Click To Expand
package.json
:# N/A
firebase.json
for react-native-firebase v6:# N/A
iOS
Click To Expand
ios/Podfile
:# N/A
AppDelegate.m
:// N/A
Android
Click To Expand
Have you converted to AndroidX?
android/gradle.settings
jetifier=true
for Android compatibility?jetifier
for react-native compatibility?android/build.gradle
:// N/A
android/app/build.gradle
:// N/A
android/settings.gradle
:// N/A
MainApplication.java
:// N/A
AndroidManifest.xml
:<!-- N/A -->
Environment
Click To Expand
react-native info
output:react-native-firebase
version you're using that has this issue:18.3.2-21.4.0
Firebase
module(s) you're using that has the issue:Database
TypeScript
?Y
&^5.0.4
React Native Firebase
andInvertase
on Twitter for updates on the library.The text was updated successfully, but these errors were encountered: