Cloud Firestore : Query nested map of arrays - firebase

My firestore document structure looks like this
doc1
{
name: 'Test',
categories: [
{
allNames: ['name1', 'name2', 'name3],
id: 'abcd'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
doc2
{
name: 'Test2',
categories: [
{
allNames: ['name7'],
id: 'abcd3'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
I am using the JS SDK and wanted to query all document with a certain category(id or name). So if I query with categories.id equal to xyz or categories.allNames contains name1, both the above documents should be returned.
Are both these queries possible or do I need to remodel my data ?
Thank you !

You cannot query arrays that way. If you know the exact object then you could use array-contains as shown below:
firestore.collection('col').where('categories', 'array-contains', {id: 'abc', allNames: ['name1']})
One solution would be to store another array which contains category IDs only like this:
{
name: 'Test1',
categories: [...],
categoryIds: ['abcd', 'xyz']
}
Now you can use arrayContains even if you know the category ID only and not the whole object in categories array. The same method can be used for allNames.
Categories can also be made a sub-collection where each object in categories array would be a document. Then you can use Collection Group queries to find category documents with that ID or allNames and find parent document ID using the DocumentReference.

Related

How to order ngrx entity collection

I have a response from backend like this:
[{ id: 4, name: 'Andrew'},
{id: 3, name: 'Rebecca'},
{id: 2, name: 'Joseph'},
{id: 1, name: 'Kristin'}]
The order is by descending id. From the last one to first one.
I have an entityAdapter defined in this way:
export const folderAdapter: EntityAdapter<Person> = createEntityAdapter<Person>({
selectId: person => person.id,
sortComparer: false,
});
into the reducer I created this function:
on(PeopleActions.loadAllPeople, (state, action): PeopleState => {
return {
...state,
people: adapter.addMany(action.people, state),
};
}),
when I go to see my state I have this situation:
ids:[4,3,2,1],
entities: {1: {id: 1, name: 'Kristin'}, 2: {id: 2, name: 'Joseph'}, 3: {id: 3, name: 'Rebecca'}, 4: { id: 4, name: 'Andrew'}}
}
This also happen into the ngFor. I tried to set return value to zero in ngfor keyvalue but nothing change. How can I change the order in entities? is there a particular property?
The EntityAdapter has the parameter sortComparer for this exact purpose.
All you need it to instead of using
sortComparer: false
you give it the function you would like to have sorting your entity ids
sortComparer: (a ,b) => a.id - b.id
As per ngrx's docs:
If provided, the state.ids array will be kept in sorted order based on comparisons of the entity objects, so that mapping over the IDs array to retrieve entities by ID should result in a sorted array of entities.
If not provided, the state.ids array will not be sorted, and no guarantees are made about the ordering. In other words, state.ids can be expected to behave like a standard Javascript array.

Flutter delete array from document [duplicate]

I'm making a Flutter application.
But, I cannot delete a field in the Firestore document.
In another language I know to use FieldValue.delete() to delete a file in Firestorm document.
In Dart, How do I delete?
Update Oct,2018: This is Now Possible:
In order to delete a particular field from a Cloud Firestore document - make sure you are using Plugin version 0.8.0 or Above. Now a E.g If you have a document having a field 'Desc' with contain some Text. In Order to Delete it.
Firestore.instance.collection('path').document('name').update({'Desc': FieldValue.delete()}).whenComplete((){
print('Field Deleted');
});
This will Delete 'Desc' Field from the Document 'name'
I think this is currently impossible in standard, non hacky way.
There is an open issue https://github.com/flutter/flutter/issues/13905 in Flutter which have to be resolved first.
Get the DocumentReference, invoke update with a map which has a key you want to delete and value FieldValue.delete().
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('document_id')
.update({
'field_to_delete': FieldValue.delete(),
}
);
Here is an official solution for deleting Field Path when programming in Flutter/Dart
Here is how a sample Firestore collection looks like:
{
'path': {
'name': {
'title': 'my title'
'description': 'my description',
}
}
}
In order to delete description field, you can do this:
Firestore.instance.collection('path').document('name').set(
{'description': FieldValue.delete()},
SetOptions(
merge: true,
),
)
And the collection will look like this:
{
'path': {
'name': {
'title': 'my title'
}
}
}
if you have nested fields then use the '.' (Dot) notation to specify the field.
E.g if your data is nested Map then this is handy.
Firestore.instance.collection('path').document('name').update({'address.town': FieldValue.delete()}).whenComplete((){
print('Field Deleted');
});

Google datastore modelling

I have two entities. Categories and Products. Each product can have many categories and each category can belong to many categories. I would like to be able to return all products and for each one to have all the categories it belongs to and their parent categories. Is datastore a good option for something like this?
example Product response:
{
id: 1,
name: "shoes",
categories: [{
id:1,
ordinal:1
},{
id:2,
ordinal:1
}]
}
I assume you meant 'Datastore' where you wrote 'dataflow'
It depends if you want to query later based on categories or not.
In case you won't need to query based on categories
I'd suggest defining your categories in a model (with the appropriate parent/child relationships) and then adding each category to a product in a LocalStructuredProperty. Datastore will save as a blob but will reconstruct the category entity model when you retrieve the product. You could also add a JsonProperty with a serialized string containing the category structure for each product. For example:
[
0: {
category: 'Electronics',
subcategories: ['Smartphones', 'Telephones', 'Gadgets']
},
1: {
category: 'Apple',
subcategories: ['iPhone']
}
]
Read more about the LocalStructuredProperty and the JsonProperty here (for Python client library).
If you need to query based on categories
Then you should use a StructuredProperty. Create a model to define your categories and their ancestor paths. Then you add one or more categories (along with their parents) to the Product entity when you instantiate it.
The Entity Property Reference in Datastore documentation has a good example of how to implement it (in Python, but also available for other languages). And here's how you filter for StructuredProperty values.

ElasticSearch filter by wildcard

I'm trying to filter my results by wildcard character.
example of my records:
....
"_source" : {
"urlSlug" : "entry-title",
"revisions" : [
{
"title" : "Entry title",
"context" : "NKD"
}
]
}
each revision can have different context with different order.
And when I search for record I want to search only entities with context like "N". So I perform nested query with match_all and wildcard.
{"query":{"bool":{"must":[{"query_string":{"query":"*entry*"}},{"nested":{"path":"revisions","query":{"bool":{"should":[{"match_all":{}}],"filter":[{"wildcard":{"revisions.context":{"value":"*N*","boost":1}}}]}}}}]}},"size":10}
When I run query I get zero results. And Can't figure out how to restrict results.
I'm using for this FosElastica with following config:
indexes:
app:
types:
entity:
properties:
urlSlug: ~
revisions:
type: "nested"
properties:
title: { type: text,boost: 10 }
context: { type: text }
and my query builder looks like this:
$boolQuery = new ESQuery\BoolQuery();
$fieldQuery = new ESQuery\QueryString();
$fieldQuery->setQuery('*' . $query . '*');
$boolQuery->addMust($fieldQuery);
$nestedQuery = new ESQuery\Nested();
$nestedQuery->setPath('revisions');
$nestedBoolQuery = new ESQuery\BoolQuery();
$matchAllQuery = new ESQuery\MatchAll();
$nestedBoolQuery->addShould($matchAllQuery);
$filterQuery = new ESQuery\Wildcard();
$filterQuery->setValue('revisions.context','*N*');
$nestedBoolQuery->addFilter($filterQuery);
$nestedQuery->setQuery($nestedBoolQuery);
$boolQuery->addMust($nestedQuery);
$result = $finder->findHybrid($boolQuery,self::AUTOCOMPLETE_MAX_RESULTS);
ElasticSearch version 5.2.2
Well I did find out what is the problem in my query.
this is working one:
{"query":{"bool":{"must":[{"query_string":{"query":"*komi*"}}],"filter":[{"nested":{"path":"revisions","query":{"wildcard":{"revisions.context":{"value":"*n*","boost":1}}}}}]}},"size":10}
whole problem was uppercase wildcard search. I was looking for *N* and have zero results and with *n* it fine.

Define Multiple-Columns as PK in YDN-DB

When define a schema with ydn-db I can define a single column as PK with this code:
var products = {
name: 'products',
keyPath: 'id_product',
autoIncrement: true,
indexes: [
{keyPath: 'id_product'},
{keyPath: 'id_supplier'}
]
};
var schema = {
stores: [products]
};
How I can define a Store (table) with one PK with two columns or more? Thanks
How I can define a Store (table) with one PK with two columns or more?
I am not sure answering your question. IndexedDB (ynd-db is very IDB centric) can have only one PK. But primary key can be compound key compose of multiple keyPath (column) using array keypath. It is define like this
var products = {
name: 'products',
keyPath: ['id_category', id_product']
};

Resources