Closed SilentAntenna closed 2 years ago
The docs say:
'contains': value must be an array and it must contain a value equal to compare, or contain all of the values in compare array
It does not say it will match all records if you pass an empty array. I think that if you pass an empty array, it should match only nodes with empty array values.
If this is not the case, or can convince me that logic should be different, let me know. Also, please provide code examples with expected and actual output, so I can add them to the unit tests.
Note: My bad. The database didn't return an empty set when compare == []
. It actually threw an uncaught error. I didn't notice that because my error handler caught it in my own code.
Nevertheless, it is still a very dangerous behavior. And the error condition is not stated in the document.
It does not say it will match all records if you pass an empty array. I think that if you pass an empty array, it should match only nodes with empty array values.
If this is not the case, or can convince me that logic should be different, let me know.
Imagine an item list with property tags
. We use query('address').filter('tags', 'contains', filter_tag_list).get()
to get the items with related tags. If we add a new element in filter_tag_list
, we will have more constraints in our query and fewer items will be returned. Now let's reverse the process. If we delete an element in filter_tag_list
, we will have less constraints in our query and get more items, if we delete all the elements in filter_tag_list
, there will be no constraint in our query at all.
Code example:
"use strict";
const { AceBase } = require('acebase');
(async () => {
let db;
const options = { logLevel: 'log', storage: { path: "./pathToDB" } };
db = new AceBase('TestDB', options);
await db.ready();
await db.ref('food').push({
name: 'apple',
tags: ['fruit', 'sweet']
});
await db.ref('food').push({
name: 'orange',
tags: ['fruit', 'sweet', 'sour']
});
await db.ref('food').push({
name: 'tomato',
tags: ['vegetable', 'sour']
});
await db.ref('food').push({
name: 'milk',
tags: ['drink', 'sweet']
});
await db.ref('food').push({
name: 'water',
tags: ['drink']
})
await db.ref('food').push({
name: 'salt',
tags: []
});
console.log('Food with tags: ["fruit", "sweet"]');
let queries = await db.query('food').filter('tags', 'contains', ['fruit', 'sweet']).get();
for(let query of queries)console.log(query.val().name);
console.log("");
console.log('Food with tags: ["sweet"]');
queries = await db.query('food').filter('tags', 'contains', ['sweet']).get();
for(let query of queries)console.log(query.val().name);
console.log("");
console.log('Food with tags: []');
queries = await db.query('food').filter('tags', 'contains', []).get();
for(let query of queries)console.log(query.val().name);
console.log("");
})();
Thanks for your detailed explanation! I'll add a unit test with your code and make appropriate adjustments.
I've made quite a few changes to the code today, managed to tackle this issue too. I'll try to release a new version within a week or so, if you'd want to test with the new codebase before then (I'm in the middle of a TypeScript port), make sure to clone both the acebase and acebase-core repositories!
The filter is working as expected now. Thanks!
According to the description of operator
contains
, whencompare == []
, the query should return all values in the database. But actually it returns nothing.Note that
compare == []
is possible in actual use. It may be followed by other query operations likesort
andtake
.