Skip to content
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

Cloud Firestore .where() in operator doesn't work for numbers #3004

Closed
3 of 10 tasks
colloquet opened this issue Dec 15, 2019 · 28 comments · Fixed by #5840
Closed
3 of 10 tasks

Cloud Firestore .where() in operator doesn't work for numbers #3004

colloquet opened this issue Dec 15, 2019 · 28 comments · Fixed by #5840
Assignees
Labels
Keep Open avoids the stale bot plugin: firestore Firebase Cloud Firestore resolution: needs-repro This issue could be reproduced or needs a repro provided. Workflow: Needs Review Pending feedback or review from a maintainer.
Milestone

Comments

@colloquet
Copy link

Issue

When using where() and in for queries, numbers does't work.

// does not work
const querySnapshot = await roomsRef.current.where('status', 'in', [1, 2]);

// after changing the field 'status' to string in Firebase console, it does work
const querySnapshot = await roomsRef.current.where('status', 'in', ['1', '2']);

In order to find out if this is react-native-firebase's bug or Firestore simply does not support in numbers, I have used the JS SDK for web to perform the same query and it worked. So I came to the conclusion that this is a bug in react-native-firebase.


Project Files

Javascript

Click To Expand

package.json:

{
  "name": "test",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@expo/react-native-action-sheet": "^3.4.1",
    "@invertase/react-native-apple-authentication": "^0.1.1",
    "@react-native-community/async-storage": "^1.7.1",
    "@react-native-community/google-signin": "^3.0.3",
    "@react-native-firebase/app": "^6.2.0",
    "@react-native-firebase/auth": "^6.2.0",
    "@react-native-firebase/firestore": "^6.2.0",
    "@react-native-firebase/functions": "^6.2.0",
    "@react-native-firebase/storage": "^6.2.0",
    "appcenter": "^2.6.0",
    "appcenter-analytics": "^2.6.0",
    "appcenter-crashes": "^2.6.0",
    "moment": "^2.24.0",
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-native-code-push": "^6.0.0",
    "react-native-fbsdk": "^1.1.1",
    "react-native-gesture-handler": "^1.5.2",
    "react-native-image-crop-picker": "^0.26.1",
    "react-native-keyboard-aware-scroll-view": "^0.9.1",
    "react-native-linear-gradient": "^2.5.6",
    "react-native-reanimated": "^1.4.0",
    "react-native-screens": "^1.0.0-alpha.23",
    "react-native-vector-icons": "^6.6.0",
    "react-navigation": "^4.0.10",
    "react-navigation-header-buttons": "^3.0.4",
    "react-navigation-stack": "^1.10.3"
  },
  "devDependencies": {
    "@babel/core": "^7.6.2",
    "@babel/runtime": "^7.6.2",
    "@react-native-community/eslint-config": "^0.0.5",
    "babel-jest": "^24.9.0",
    "eslint": "^6.5.1",
    "flow-bin": "^0.113.0",
    "jest": "^24.9.0",
    "metro-react-native-babel-preset": "^0.56.0",
    "react-test-renderer": "16.9.0"
  },
  "jest": {
    "preset": "react-native"
  }
}

firebase.json for react-native-firebase v6:

{
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  }
}

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

target 'Test' do
  # Pods for Test
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
  pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
  pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
  pod 'React', :path => '../node_modules/react-native/'
  pod 'React-Core', :path => '../node_modules/react-native/'
  pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
  pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
  pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
  pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'

  pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
  pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
  pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
  pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'

  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

  # Facebook SDK
  pod 'FBSDKCoreKit'
  pod 'FBSDKLoginKit'

  # Google Signin SDL
  pod 'GoogleSignIn', '~> 5.0.2'

  # react-native-image-crop-picker
  pod 'QBImagePickerController', :path => '../node_modules/react-native-image-crop-picker/ios/QBImagePicker/QBImagePickerController.podspec'

  target 'TestTests' do
    inherit! :search_paths
    # Pods for testing
  end

  use_native_modules!
end

target 'Test-tvOS' do
  # Pods for Test-tvOS

  target 'HeroRN-tvOSTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

AppDelegate.m:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

@import Firebase;
#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <RNGoogleSignin/RNGoogleSignin.h>
#import <AppCenterReactNative.h>
#import <AppCenterReactNativeAnalytics.h>
#import <AppCenterReactNativeCrashes.h>
#import <CodePush/CodePush.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"Test"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  
  if ([FIRApp defaultApp] == nil) {
    [FIRApp configure];
  }
  [[FBSDKApplicationDelegate sharedInstance] application:application
  didFinishLaunchingWithOptions:launchOptions];
  [AppCenterReactNative register];
  [AppCenterReactNativeAnalytics registerWithInitiallyEnabled:true];
  [AppCenterReactNativeCrashes registerWithAutomaticProcessing];
  return YES;
}

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

  BOOL handled =  [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options] || [RNGoogleSignin application:application openURL:url options:options];
  // Add any custom logic here.
  return handled;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [CodePush bundleURL];
#endif
}

@end


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = "28.0.3"
        minSdkVersion = 16
        compileSdkVersion = 28
        targetSdkVersion = 28
        googlePlayServicesAuthVersion = "16.0.1"
    }
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:3.4.2")
        classpath("com.google.gms:google-services:4.3.3")

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        mavenLocal()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url("$rootDir/../node_modules/react-native/android")
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }

        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

android/app/build.gradle:

apply plugin: "com.android.application"

import com.android.build.OutputFile

/**
 * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
 * and bundleReleaseJsAndAssets).
 * These basically call `react-native bundle` with the correct arguments during the Android build
 * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
 * bundle directly from the development server. Below you can see all the possible configurations
 * and their defaults. If you decide to add a configuration block, make sure to add it before the
 * `apply from: "../../node_modules/react-native/react.gradle"` line.
 *
 * project.ext.react = [
 *   // the name of the generated asset file containing your JS bundle
 *   bundleAssetName: "index.android.bundle",
 *
 *   // the entry file for bundle generation
 *   entryFile: "index.android.js",
 *
 *   // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
 *   bundleCommand: "ram-bundle",
 *
 *   // whether to bundle JS and assets in debug mode
 *   bundleInDebug: false,
 *
 *   // whether to bundle JS and assets in release mode
 *   bundleInRelease: true,
 *
 *   // whether to bundle JS and assets in another build variant (if configured).
 *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
 *   // The configuration property can be in the following formats
 *   //         'bundleIn${productFlavor}${buildType}'
 *   //         'bundleIn${buildType}'
 *   // bundleInFreeDebug: true,
 *   // bundleInPaidRelease: true,
 *   // bundleInBeta: true,
 *
 *   // whether to disable dev mode in custom build variants (by default only disabled in release)
 *   // for example: to disable dev mode in the staging build type (if configured)
 *   devDisabledInStaging: true,
 *   // The configuration property can be in the following formats
 *   //         'devDisabledIn${productFlavor}${buildType}'
 *   //         'devDisabledIn${buildType}'
 *
 *   // the root of your project, i.e. where "package.json" lives
 *   root: "../../",
 *
 *   // where to put the JS bundle asset in debug mode
 *   jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
 *
 *   // where to put the JS bundle asset in release mode
 *   jsBundleDirRelease: "$buildDir/intermediates/assets/release",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in debug mode
 *   resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in release mode
 *   resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
 *
 *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means
 *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
 *   // date; if you have any other folders that you want to ignore for performance reasons (gradle
 *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
 *   // for example, you might want to remove it from here.
 *   inputExcludes: ["android/**", "ios/**"],
 *
 *   // override which node gets called and with what additional arguments
 *   nodeExecutableAndArgs: ["node"],
 *
 *   // supply additional arguments to the packager
 *   extraPackagerArgs: []
 * ]
 */

project.ext.react = [
    entryFile: "index.js",
    enableHermes: false,  // clean and rebuild if changing
]

project.ext.vectoricons = [
    iconFontNames: ['Feather.ttf']
]

apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

/**
 * Set this to true to create two separate APKs instead of one:
 *   - An APK that only works on ARM devices
 *   - An APK that only works on x86 devices
 * The advantage is the size of the APK is reduced by about 4MB.
 * Upload all the APKs to the Play Store and people will download
 * the correct one based on the CPU architecture of their device.
 */
def enableSeparateBuildPerCPUArchitecture = false

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = false

/**
 * The preferred build flavor of JavaScriptCore.
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US.  Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'

/**
 * Whether to enable the Hermes VM.
 *
 * This should be set on project.ext.react and mirrored here.  If it is not set
 * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
 * and the benefits of using Hermes will therefore be sharply reduced.
 */
def enableHermes = project.ext.react.get("enableHermes", false);

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    dexOptions {
        javaMaxHeapSize "4g"
    }

    defaultConfig {
        applicationId "com.test.test"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
        release {
            if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
                storeFile file(MYAPP_UPLOAD_STORE_FILE)
                storePassword MYAPP_UPLOAD_STORE_PASSWORD
                keyAlias MYAPP_UPLOAD_KEY_ALIAS
                keyPassword MYAPP_UPLOAD_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://facebook.github.io/react-native/docs/signed-apk-android.
            signingConfig signingConfigs.release
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }

        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.facebook.react:react-native:+"  // From node_modules
    implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
    implementation 'androidx.multidex:multidex:2.0.1'

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.gms.google-services'

android/settings.gradle:

rootProject.name = 'Test'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

MainApplication.java:

package com.test.test;

import androidx.multidex.MultiDexApplication;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import com.microsoft.codepush.react.CodePush;

public class MainApplication extends MultiDexApplication implements ReactApplication {

  private final ReactNativeHost mReactNativeHost =
      new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this); // Remove this line if you don't want Flipper enabled
  }

  /**
   * Loads Flipper in React Native templates.
   *
   * @param context
   */
  private static void initializeFlipper(Context context) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
        aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.test.test">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustPan">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
      <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id" />
    </application>

</manifest>


Environment

Click To Expand

react-native info output:

System:
    OS: macOS 10.15.2
    CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
    Memory: 112.74 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 13.3.0 - /usr/local/bin/node
    Yarn: 1.21.1 - /usr/local/bin/yarn
    npm: 6.13.2 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 23, 26, 27, 28
      Build Tools: 23.0.1, 26.0.2, 27.0.3, 28.0.1, 28.0.3
      System Images: android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.5977832
    Xcode: 11.3/11C29 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0 
    react-native: 0.61.5 => 0.61.5
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • 6.2.0
  • Firebase module(s) you're using that has the issue:
    • Firestore
  • Are you using TypeScript?
    • N


Think react-native-firebase is great? Please consider supporting all of the project maintainers and contributors by donating via our Open Collective where all contributors can submit expenses. [Learn More]

@mikehardy
Copy link
Collaborator

Interesting - the javascript seems to be just feeding the modifiers to native

So - android or ios?

I'm better at Java, so I see it flowing down to here:

I'm guessing something coming out there is unexpected, and some judicious use of "System.out.println()" inside node_modules in there might turn up the problem

@colloquet
Copy link
Author

@mikehardy I have done some more research on this bug and here's what I have found:

  • It's working again after I changed ReactNativeFirebaseFirestoreSerialize.java:429 from getDouble to getInt

  • I tried using the Flutter Firebase SDK and it works fine so I looked at their source code and it looks like they do not change the type of value when passing into the whereIn query.

Is it necessary to use the type map when passing the query parameter from JS to native?

@Ehesp
Copy link
Member

Ehesp commented Dec 16, 2019

The problem with doing getInt is it won't work for doubles. Let me have a think, should be easy enough to sort.

Is it necessary to use the type map when passing the query parameter from JS to native?

This is for performance, the data being sent over the bridge is pretty massive so the conversion slims it down.

@colloquet
Copy link
Author

@Ehesp I see, that make sense.

So to fix this the code should distinguish between int and double on the JS side and then add another type on both sides?

@Ehesp
Copy link
Member

Ehesp commented Dec 16, 2019

Yeah, grab as a double, check if it is actually a double - if not, typecast as int maybe? Need to have a play.

@Salakar Salakar added this to the v6.3.0 milestone Dec 16, 2019
@stale
Copy link

stale bot commented Jan 13, 2020

Hello 👋, to help manage issues we automatically close stale issues.
This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs.
Thank you for your contributions.

@stale stale bot added the Type: Stale Issue has become stale - automatically added by Stale bot label Jan 13, 2020
@Salakar Salakar added the Keep Open avoids the stale bot label Jan 20, 2020
@stale stale bot removed the Type: Stale Issue has become stale - automatically added by Stale bot label Jan 20, 2020
@Salakar Salakar added Version: 6.x.x plugin: firestore Firebase Cloud Firestore labels Jan 20, 2020
@Ehesp Ehesp added the resolution: fixed A fix has been merged into master. label Feb 3, 2020
@Ehesp
Copy link
Member

Ehesp commented Feb 3, 2020

Just pushed up a fix - will get a release out soon.

@Ehesp Ehesp closed this as completed Feb 3, 2020
@colloquet
Copy link
Author

@Ehesp Hi, I have just updated the library and its working on Android now, thanks! Any idea when will this be fixed on the iOS side as well?

Thanks!

@mokoshi
Copy link

mokoshi commented Jun 8, 2020

@Ehesp I'm also facing with the same problem. It is working fine on Android, but on iOS the where() in query with numbers ends up with 0 results.

    "@react-native-firebase/app": "^7.1.4",
    "@react-native-firebase/firestore": "^7.1.2",

@CesarRivasP
Copy link

CesarRivasP commented Jun 26, 2020

@Ehesp I'm also facing with the same problem. It is working fine on Android, but on iOS the where() in query with numbers ends up with 0 results.

    "@react-native-firebase/app": "^7.1.4",
    "@react-native-firebase/firestore": "^7.1.2",

Currently, I have the same problem when using a clause similar to

 .where ("participants", "array-contains", 154)

it is maintained without returning results, even if there are any.
Try testing updating the firebase SDK to version 6.27.0, and the error still persists

@Salakar Salakar reopened this Jun 26, 2020
@Salakar
Copy link
Member

Salakar commented Jun 26, 2020

cc @Ehesp looks like this is also not working on iOS

@dackers86
Copy link
Member

Initial PR added at #3895

@dackers86
Copy link
Member

dackers86 commented Jul 15, 2020

Additional tests added that confirm the issue has been resolved. Please feel free to reopen if the issue can be replicated

@nitishxyz
Copy link

nitishxyz commented Aug 17, 2020

still not working on iOS, any workarounds?

@dackers86
Copy link
Member

HI @nitnk9.

Can you provide an example and perhaps some input which shows this is incorrect. This may be an edge case we have not considered yet?

@dackers86 dackers86 reopened this Aug 17, 2020
@nitishxyz
Copy link

It was probably a firebase backend error. The problem was with where in query for array of integers, I changed my code base to work with strings, but now it seems to work with integers too.

@mikehardy
Copy link
Collaborator

Very strange. Okay, if we can get a reproduction case (a simple App.js or something) that reproduces it in the future we can always reopen - glad you're moving forward!

@ahanusek
Copy link

ahanusek commented Jan 28, 2021

This issue is still occurring:

const snapshot = await ref .where('phoneNumbers', 'array-contains', 48123456789) .get();

Above query properly works on Android but on iOS always return empty collection. When changing data model to array with strings then works perfectly fine.

@mikehardy
Copy link
Collaborator

Very strange. Okay, if we can get a reproduction case (a simple App.js or something) that reproduces it in the future we can always reopen - glad you're moving forward!

My previous comment is still valid - but even more importantly it sounds like you have a repro case - if you reach right into node_modules the objective-c isn't that hard to work with, you can log what exactly is being sent as a query and it might be a trivial fix?

@adapptorsimon
Copy link

I just got bitten by the change in commit 13a6560.

I don't believe this can be the correct fix. As it is now, Android and iOS send different objects for the same RN code -- which I'm sure should never happen.

The result in my case was that a Cloud Function I wrote to read new documents worked on one platform but not the other. Even though the documents appear the same in the Firestore console, they're not identical: in Android-created documents, the value appears in the integerValue field; for iOS, it comes through in the doubleValue field.

(For now, I will stringify numbers before sending them, but this is obviously not a reasonable long term solution.)

@mikehardy mikehardy reopened this Mar 16, 2021
@mikehardy
Copy link
Collaborator

@adapptorsimon what you describe should not happen, no - if you have a patch for Obj-C that would harmonize the two that would be helpful 🙏

@mikehardy mikehardy added the Workflow: Needs Review Pending feedback or review from a maintainer. label Apr 5, 2021
@Davidson-Mike
Copy link

Davidson-Mike commented Jun 15, 2021

Hello - I noticed this is marked as 'Resolution: Fixed' so I just wanted to share that it definitely is not resolved.

On iOS it is entirely impossible to call a with() in on an array of numbers, as the results list is always empty. This is a basic principle of Firestore and our production content is impacted. The only reason your testing is passing is because you create the document in iOS which passes along the same doubleValue. If you create the document in android, then try to do this query on it in iOS, it will fail.

Now we are evaluating having to change the format of our datastore to use strings in stead of numbers in order to correct a bug within this library which, frankly, is unfortunate. Our datastore is already populated with production data.

@mikehardy
Copy link
Collaborator

Very strange. Okay, if we can get a reproduction case (a simple App.js or something) that reproduces it in the future we can always reopen - glad you're moving forward!

My previous comment is still valid - but even more importantly it sounds like you have a repro case - if you reach right into node_modules the objective-c isn't that hard to work with, you can log what exactly is being sent as a query and it might be a trivial fix?

@Davidson-Mike my previous previous comment is still valid ☝️

@mikehardy mikehardy added resolution: needs-repro This issue could be reproduced or needs a repro provided. and removed resolution: fixed A fix has been merged into master. labels Jun 15, 2021
@Davidson-Mike
Copy link

Davidson-Mike commented Jun 15, 2021

@Davidson-Mike my previous previous comment is still valid ☝️

Hi Mike - I understand your desire for an easily executable snippit to debug this issue. Unfortunately the issue with creating an easily reproducible example is that the issue itself can not be easily reproduced through something like a test.

This is because if you create the document using this library, on iOS, then it will succeed in querying the result. The issue is present if the document was created through another source. Obviously I don't believe it is intended for this library to only be fully compatible with records it makes itself for iOS, on iOS.

In order to consistently reproduce this issue you must create the document through something like the Firebase Console or another Firebase API. Personally - I have re-created the issue consistently by creating the document via the official Google.Cloud.Firestore .NET API.

Here's an example doc;
image

Attempting this query would then return an empty array on iOS while working fine on Android;
const results = (await firestore().collection('yourCollection').where('example', 'in', [100, 500]).get()).docs;

I hope this provides enough information for you to more easily debug this issue, and hope you understand that I would happily provide you a simple example if I could but at the very least it would have to be two separate and different examples run in sequence on different platforms. I suppose I can do that if this still wasn't enough - let me know.

@mikehardy
Copy link
Collaborator

You indicate that if you create it on android it will then fail on ios, in a react-native context that means that in one sample app.js you could have a create doc / fetch doc for platform android, and on ios you could have a fetch and it would reproduce I think? That would allow for a manual look at it - I imagine the thing is going to be trivially small as a repro, but exchanging executable code vs prose is always more efficient if at all possible

Not sure how to exercise this in the e2e harness except via a cloud function that generated the data we expect to work, followed by android + ios fetching it (with android expected working ios expected failing, on the problematic input)

@Davidson-Mike
Copy link

Davidson-Mike commented Jun 15, 2021

@mikehardy yes, that is correct.

I created the example per your request, tested, and have confirmed that it recreates the issue every time.

I also confirmed that after changing the type manually in firebase to a String (and updating the array in code) the issue is resolved. I then changed it back to a 'Number' and it went back to returning no results.

Obviously you will need a react-native project bootstrapped, as well as Firebase/Firestore configured. I created a collection called 'exampleCollection' and nothing more.

First run the example on Android, it will print a success message. Then run it on ios where it will print a result size.

App.js;

import React from 'react';
import {Platform, Text, SafeAreaView} from 'react-native';
import firestore from '@react-native-firebase/firestore';

const App = () => {
  if (Platform.OS === 'android') {
    firestore()
      .collection('exampleCollection')
      .add({
        id: 500,
        age: 30,
      })
      .then(() => {
        console.log('Example added!');
      })
      .catch(r => console.log(r));
  } else if (Platform.OS === 'ios') {
    firestore()
      .collection('exampleCollection')
      .where('id', 'in', [100, 500])
      .get()
      .then(v => console.log(`Result size: ${v.docs.length}`));
  }

  return (
    <SafeAreaView>
      <Text>Hello World</Text>
    </SafeAreaView>
  );
};

export default App;

androidIsForVivek pushed a commit to androidIsForVivek/react-native-firebase that referenced this issue Aug 9, 2021
mikehardy added a commit that referenced this issue Nov 24, 2021
validate that types go into and come out of firestore consistently
using different SDKs

WIP because this is giving a false-positive so far: we should be able to pinpoint the problem from #3004 and targeted by #5840
mikehardy added a commit that referenced this issue Nov 24, 2021
validate that types go into and come out of firestore consistently
using different SDKs

This probes the problem from #3004
mikehardy pushed a commit that referenced this issue Dec 14, 2021
* feat(firestore): fix iOS Long/Double conversion #3004
* Add special -0 handling
* Add tests

Co-Authored-By: Mike Hardy <github@mikehardy.net>

BREAKING CHANGE: Previous versions of firestore here incorrectly saved integers as doubles on iOS, so they did not show up in `where`/`in` queries. You had to save numbers as strings if you wanted `where`/`in` queries to work cross-platform. Number types will now be handled correctly. However, If you have integers saved (incorrectly!) as double (from previous versions) and you use where / in style queries on numbers, then the same document will no longer be found via .where. Mitigation could be to go through your whole DB and load and re-save the integers correctly, or alter queries. Please test your where / in queries that use number types if this affects you.
@sheggietyn
Copy link

i got a problem, i will like to check if a userId or a UserIDD === to the persons user.uid in firestore then document should display

the or is not working I used this for or ||

code below

.where(
'userID', '==', user.uid, || 'userId' '==',user.uid,
)

is it possible to do this .. if not how else can I go about it

@mikehardy
Copy link
Collaborator

@sheggietyn not sure why it isn't working for you but I do that all the time. This is the line from my production app, authUser is the user from @react-native-firebase/auth, I've stored the id in a firebase users collection as fbAuthId and compare them like so, works fine

src//app/hooks/useUserInfo.tsx: .where('fbAuthId', '==', authUser?.uid)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Keep Open avoids the stale bot plugin: firestore Firebase Cloud Firestore resolution: needs-repro This issue could be reproduced or needs a repro provided. Workflow: Needs Review Pending feedback or review from a maintainer.
Projects
None yet
Development

Successfully merging a pull request may close this issue.