How to query documents where contains an array and the value of the array is ["val1", "val2"] Firestore - firebase

How can I get a collection where the query should be applicable to an array inside the document.
Document example: I would like to know how to query the document where the brands are fiat and seat
{
"name":"test 1",
"brands":[
{
"brand":{
"id":1,
"name":"Fiat",
"slug":"fiat",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":2,
"name":"Seat",
"slug":"seat",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":3,
"name":"Mercedes",
"slug":"mercedes",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
},
{
"brand":{
"id":4,
"name":"Yamaha",
"slug":"yamaha",
"image":null,
"year_end":null,
"year_start":null
},
"released_at":"2018-10-26"
}
]
}
I have tried something like:
.collection("motors")
.where("brands.slug", "array-contains-any", ["fiat", "seat"])
but this is not working I cannot figure out by the documentation how to get this.

When using the array-contains-any operator, you can check the values of your array against the value of a property of type String and not an array. There is currently no way you can use array-contains-any operator on an array. There are two options, one would be to create two separate fields and create two separate queries or, been only a document, you can get the entire document and filter the data on the client.
Edit:
What #FrankvanPuffelen has commented is correct, I made some research and I found that we can check against any type and even complex types, not just against strings, as mentioned before. The key to solving this issue is to match the entire object, meaning all properties of that object and not just a partial match, for example, one of three properties.
What you are trying to achieve is not working with your current database structure because your slug property exists in an object that is nested within the actual object that exists in your array. A possible solution might also be to duplicate some data and add only the desired values into an array and use the array-contains-any operator on this new creatded array.

Related

firebase how to query through array of objects [duplicate]

This question already has answers here:
How to use array-contains operator with an array of objects in Firestore?
(2 answers)
Firestore - query where filter of object in array field
(1 answer)
Closed 10 days ago.
I need to write a query for Firestore which will filter records based on id in the array, so I have a collection of "assignments" and each assignment has records more or less like this:
{
"name" :"abc",
"status": "accepted",
"assignedAt": "timestamp",
"createdAt": "timestamp",
"recipients": [
{
id: "123",
name: "recipient1"
},
{
id: "456",
name: "recipient2"
}
]
}
I wish to write a query that will check if user.id exists as an id in the recipients array, except that I also filter out some statuses but this part works, so far I have something like this:
assignmentCollection
// .where('recipients', 'array-contains', user!.id)
.where('status', 'not-in', recipientAssignmentSkippableStatuses)
.orderBy('status', 'desc')
.orderBy('assignedAt', 'desc')
.orderBy('createdAt', 'asc')
I tried to use something called "array-contains" but:
a) it didn't work
b) it cause error that cannot be used together with "not-in"
EDIT: I found out that array-contains doesn't work as I need to pass the whole object for that, thing is that at this moment I know only the ID of the user so I need to find some workaround
I found out that array-contains doesn't work as I need to pass the whole object for that, the thing is that at this moment I know only the ID of the user so I need to find some workaround.
Yes, in order to return documents that contain a particular object in the array, you need to pass the entire object as an argument, not only a single field.
If you need to filter based on the user ID, then you should consider creating an additional array that only contains user IDs. Then you'll be able to call:
.where('userIds', 'array-contains', user!.id)

Filtering Firebase Firestore document's array of maps

I have a field named cartons in a document which is an array of maps.
**each document in a collection
**document-1
{ lotNo: 'alg-100',
cartons:[
{cartonNo:01, trackingNo:'a'},
{cartonNo:02, trackingNo:'b'},
{cartonNo:03, trackingNo:'c'},
{cartonNo:04, trackingNo:'a'}
]
}
**document-2
{ lotNo: 'alg-101',
cartons:[
{cartonNo:01, trackingNo:'a'},
{cartonNo:02, trackingNo:'b'},
{cartonNo:03, trackingNo:'c'},
{cartonNo:04, trackingNo:'a'}
]
}
what I need is only the carton object where trackingNo='a' from each document. As far I know I can't get partial data from a firestore document(either get the full document on not). So to get the carton object of similar trackingNo from different documents I am assuming get both of the documents then filter the data in client-side. Or is there any better way? what could be the best possible solution for achieving only the carton that has a similar trackingNo(as an array) from different documents ( without changing the data structure as my app is heavily relying on this particular data structure)?
Unfortunately you can't index based on properties inside of an array. In the Realtime Database, properties of an array could be indexed as cartons.<index>.trackingNo (e.g. cartons.0.trackingNo), but if you queried this, you would only get documents that contain the requested tracking number as their first carton entry. To get all results, you would need to query again for each subsequent index - cartons.1.trackingNo, cartons.2.trackingNo, and so on.
If the data is as simple as you have shown, the best option would be to tweak your data structure slightly so that you also store a list of tracking numbers in the given lot. This will allow you to perform array-contains queries on a trackingNos property.
{
lotNo: 'alg-101',
cartons: [
{ cartonNo: 01, trackingNo: 'a' },
{ cartonNo: 02, trackingNo: 'b' },
{ cartonNo: 03, trackingNo: 'c' },
{ cartonNo: 04, trackingNo: 'a' }
],
trackingNos: [
'a',
'b',
'c'
]
}
If your data has been simplified to be posted here, you might be better off with a restructure of your database where each carton is a member of the lot document's subcollection called cartons (i.e. .../lots/alg-101/cartons/01) and combined with a collection group query.

Firestore rule does not work trying to list collection when trying to read resource.data values

Simple scenario:
I have a collection named "foo"
It has a single document with the ID of "bar"
"bar" has a single string field named "sample" with the value "fail"
If I try something like this in my ruleset:
service cloud.firestore {
match /databases/{database}/documents {
// Test rule
match /foo/{id} {
allow read: if resource.data.sample == 'fail';
}
}
}
It is able to query on "bar" when I specify the document ID in the query, but if I try to list all items the query comes back with "Missing or insufficient permissions.". I also tried allow read: if get(/databases/$(database)/documents/foo/$(id)).data.sample == 'fail'; and I get the same results.
There's only a single record in the collection, I'm able to query on it individually when I reference the data ID. I understand that for a query work properly, the filter conditions need to match the rules. In this case, I'm not applying any filter, but all (1) records should be returned.
I'm having a hard time trying to find solutions on this. All the solutions I've seen say that the query results need to match the rules, and they should match in this case.
I have no idea what was going on, but it appears to be working now. I didn't change anything to make it work. The test code I was using was very simple via the web API:
function test() { firebase.firestore().collection("foo").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
}); });} test();

inserting a nested attributes array element in dynamodb table without retrieving the entire item

looking for an answer to this question if possible, not looking for a refactoring advice or redesign, i just need to understand what else I am missing here :
I have an existing item in dynamodb:
{
"CartId": 321,
"UserId": usr555,
"CartItems": [
{
"ProductId":59999,
"Quantity": 1
},
{
"ProductId": 58888,
"Quantity": 2
}
]
}
in my code I want to insert another nested attribute into the array CartItems in the item above. i can't find a way of doing this without retrieving the entire item and then inserting, which could amount to KBs in size.
all I want to do is insert a single array element in an existing nested attribute without having to retrieve the item.
the language I am using is nodejs and the function is DynamoDB.put.
UpdateExpression attribute supports SET action and SET action supports list_append function. Since list_append function operands must be list, enclose the new value within a list as below.
response = dynamodb_client.update_item(TableName='your_table',
Key={'CartId':'321'},
UpdateExpression='SET CartItems = list_append(CartItems, :val1)',
ExpressionAttributeValues = {':val1':[{'ProductId':12345, 'Quantity': 100}]})
Hope this helps

Normalizr and recursive nested structure

I'm using normalizr to flatten a structure like the following one:
{
"fields":[{
"id":"29",
"text": "something"
}, {
"id":"16",
"text": "something"
"fields":[{
"id":"17",
"text": "something"
}]
}, {
"id":"18",
"text": "something"
}
}
My structure has an array of fields and a field may also have nested fields. There's only one level of nesting allowed.
What I'm trying to do is this:
const block = new schema.Entity('fields')
const blockList = new schema.Array(block)
block.define({
fields: blockList
})
const normalizedData = normalize(originalData, blockList)
After running this snippet, normalizedData has a results property and it only has the first level of field ids, even though entities has all the fields normalized, including the nested ones.
I'd like to have in the results array all the ids, including the nested ones. What am I missing?
I'd like to have in the results array all the ids, including the nested ones. What am I missing?
This is how Normalizr works. The returned result is always in the same format of the input data. You won't be able to get what you are asking for from Normalizr.
If, however, you're just looking for a list of blocks, pull that from the entities:
const blockIds = Object.keys(normalizedData.entities.blocks);
You should consider using a normalized form for your data structure in redux.
This is advisable if your application need growth in complexity.
There is an interesting article on redux docs.
http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
A normalized form take some ideas from db counterpart and Normalizr works in that way, so your request does not really match with how Normalizr works.
Please consider #Paul Armstrong answer for a work around if you really need get blocks in that way.

Resources