firebase / firebase/firebase-tools

[firestore-emulator: datastore-mode] Unexpected response from query filter on nested property in array

Open
#7,677 3 comments 3 reactions 1 assignee Claimed by @harshyyy21 View on GitHub
emulators: firestore reproducible type: bug
Dominant language
TypeScript
Stars
4.5k
Forks
1.3k
Avg merge
1d 12h
Merged PRs (30d)
84

Description

### [REQUIRED] Environment info

**gcloud:** v493.0.0

**Platform:** Ubuntu

### [REQUIRED] Test case

**package.json**

```json
{
"version": "1.0.0",
"description": "",
"main": "lib/index.js",
"scripts": {
"build": "tsc",
"start": "DATASTORE_EMULATOR_HOST=127.0.0.1:8080 node lib/index.js",
"start:emulator:old": "gcloud --project=dummy-project-id beta emulators datastore start --use-firestore-in-datastore-mode --host-port=127.0.0.1:8080",
"start:emulator:new": "gcloud emulators firestore start --database-mode=datastore-mode --host-port=127.0.0.1:8080"
},
"devDependencies": {
"@google-cloud/datastore": "^9.1.0",
"typescript": "^5.4.3"
}
}
```

**src/index.ts**

```ts
import {and, Datastore, PropertyFilter} from "@google-cloud/datastore";

const datastore = new Datastore({
projectId: "dummy-project-id",
});

const KIND_USER = 'User'

type User = {
email: string
fields : {
key: string,
value: string,
}[]
}

export async function getUsersByName(name: string) {
const query = datastore.createQuery(KIND_USER).filter(and([
new PropertyFilter('fields.key','=','name'),
new PropertyFilter('fields.value','=',name),
]));
const [entities] = await datastore.runQuery(query);
return entities
}

export async function addUser(data: User) {
const key = datastore.key(KIND_USER);
const entity = {
key: key,
data,
};
await datastore.save(entity);
}

async function main() {
await addUser({email: "foo@example.com", fields: [{key: "name", value: "Awesome Name"}]})

const users = await getUsersByName("Awesome Name");
console.log(users);
}

main();
```

**tsconfig.json**
```json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "lib"
},
"include": ["src"],
"exclude": []
}
```

### [REQUIRED] Steps to reproduce

**Datastore Emulator (Old)**

```
npm install
npm run start:emulator:old
```

```
$ npm run build && npm run start

> build
> tsc

> start
> DATASTORE_EMULATOR_HOST=127.0.0.1:8080 node lib/index.js

[
{
fields: [ [Object] ],
email: 'foo@example.com',
[Symbol(KEY)]: Key {
namespace: undefined,
id: '1',
kind: 'User',
path: [Getter]
}
},
]
```

**Firestore Emulator (New, Preview)**

```
npm install
npm run start:emulator:new
```

```
$ npm run build && npm run start

> build
> tsc

> start
> DATASTORE_EMULATOR_HOST=127.0.0.1:8080 node lib/index.js

[]
```

### [REQUIRED] Expected behavior

```
[
{
fields: [ [Object] ],
email: 'foo@example.com',
[Symbol(KEY)]: Key {
namespace: undefined,
id: '1',
kind: 'User',
path: [Getter]
}
},
]
```

### [REQUIRED] Actual behavior

The result filtered by `fields.name` and `fields.value` should include the user, but not when using the new emulator.

```
[]
```

This issue slightly differs from https://github.com/firebase/firebase-tools/issues/6999, as the `fields` property is an array here.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.