RethinkDB get all and order with index - rethinkdb

I have an object like this:
Company {
Enable bool
Pro bool
Type int
Categories []int
}
So, how can I make query to retrieve all objects that Enable=true, Categories contains, for example, "1" and order by Pro and Type.
I have more than 200,000 records so I have to to that efficient with indexes.
I try to use this:
r.db("test_main").table("companies").indexCreate("ListAll", function(comp) {
return comp("Categories").map(function(cat) {
return [ comp("Pro"), comp("CompType"), comp("Enabled"), cat ];
});
}, {multi: true})
r.db("test_main").table("companies").between([false, 0, true, 1],
[r.maxval, r.maxval, true, 1], {index:"ListAll"}).orderBy({index:r.desc("ListAll")}).limit(100)
But categories doesn't match.

Related

Laravel - Assert json array ids using wildcard

In my application I have a response like this:
{
"items": [
{
"id": 10,
"field": "foo"
},
{
"id": 20,
"field": "bar"
}
]
}
I need to test the content of items and validate each id.
I've tried many solutions but no one works, for example (this is just a kind of pseudo-code):
assertJson(fn (AssertableJson $json) =>
$json->where('items.*.id', [10, 20])
)
Is there a way to use a wildcard to pick every ID and validate using an array?
You can use array_filter:
$idArray = [10, 20];
$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object
// Filter the items for items that aren't in the ID list
$invalidItems = array_filter($items, function ($el) {
// If the item has an id which isn't in the array, return true
return !in_array($el["id"], $idArray);
});
// This returns true if we found 0 items with IDs not in the ID list
return $invalidItems == [];
You can similarly use array_map to simplify your array, then compare it to your ID array:
$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object
$outIdArray = array_map(function($el) {
return $el["id"];
}, $items);
// Compare $outIdArray to [10, 20]
Not tested yet but below should work.
We attach an each on each child element under items and add a callback to where on that id key of each child.
<?php
assertJson(fn (AssertableJson $json) =>
$json->each('items', fn (AssertableJson $childJson) =>
$childJson->where('id', fn($idVal) =>
in_array($idVal, [10,20])
)
)
)

Updating Apollo Cache Without Variables

Originally, I make a GraphQL call as follows:
query getItems($filter_ids: [Int!], $filter: item_records_bool_exp) {
items(order_by: { negative: asc, parent: asc }, where: { level: { _in: [2, 3] } }) {
i18n {
value
}
id
parent
negative
}
filters(where: { category: { _eq: "PLAN" } }) {
id
value
}
}
Now, when I insert a new item, I update the cache using update function in the mutation options, and I'm supposed to use readQuery/readFragment and writeQuery/writeFragment to interact with the Apollo Cache as described here.
My question is, my readQuery calls always fail if I do not provide the exact same variables that I had previous provided to the original GraphQL query. Is there a way around this? In other words, can I just read objects from the cache by their ID irrespective of the original query that was used to fetch these objects?

Mixing user data with ElasticSearch

I'm using ElasticSearch to store listings. The user can sort by multiple fields (e.g. grossReturn, buyingPrice) etc.
Now we want to offer the option, that the user can store favorite listings.
Am storing the favorites in PostgresSQL. Then before each request I'm getting the favorites from Postgres - putting them in an array and have a scripted field like so:
const scripts = {
favorite: {
script: {
source: 'return params.favorites.contains(params._source.id) ? 1 : 0',
params: {
favorites,
},
},
},
};
Now I also want to sort by this field and this is the problem:
const getSortParams = (sortBy, scripts) => {
const sort = {};
if (sortBy) {
const fieldName = sortBy.split(',')[0];
const sortOrder = sortBy.split(',')[1];
if (fieldName === 'favorite') {
sort._script = {
type: 'number',
script: scripts[fieldName].script,
order: sortOrder,
};
} else {
sort[fieldName] = {
order: sortOrder,
};
}
}
return sort;
};
It is very very slow - sorting taking roughly 3s. It makes sense since everything needs to be calculated.
My question would be -> what is a better way to do this?
Add a property to your listing definition class that would indicate whether it's a favourite or not (true, false).
Since its per user basis, maybe add an array property for your user model that would store an array of favourite listing ids.

Why isn't my $sort Operator on dates function consistent in my query?

I am trying to write a query to sort out documents based on descending dates ...{sort: {paymentDate: -1 }} order. The first time the query runs, the query section {sort: {paymentDate: -1 }} seems get ignored!
However when I refresh the page in the browser, the query section {sort: {paymentDate: -1 }} is applied, and the query displays in the correct sort order.
I need to know how to correct this issue!
Find below the contents of my document after I run the recipientsDetails.find().fetch(); query in the browser console:
0:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-11 02:37:05"
payersNumber: "+25478887633"
paymentStatus: "Failed"
recipientNumber: "+25478887633"
_id: "eFShDRzp9JM9ejG5S"
1:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-08 16:02:25"
payersNumber: "+2547078887633"
paymentStatus: "Failed"
recipientNumber: "+25478887633"
_id: "SnpNwsx49mZfPNSg7"
2:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-08 15:00:02"
payersNumber: "+254707888633"
paymentStatus: "Failed"
recipientNumber: "+25478087703"
_id: "ZHWSiRBYk2xoZvDzb"
The above results is also the desired sorted order.
Perhaps the below helper code might shade some light.
../client/main.js
Template.paymentB2C.helpers({
'enableButton': function () {
var enableButtonStatusArray = [];
var userIdCode = Meteor.userId();
var phoneNumber = Meteor.users.findOne({_id: userIdCode }, { fields: { "profile.telephoneNumber": 1 } } );
var usersPhoneNumber = phoneNumber.profile.telephoneNumber;
var selectedRecipientDetails = recipientsDetails.find( { $or: [ { payersNumber: usersPhoneNumber }, { recipientNumber: usersPhoneNumber } ] },
{ fields: {
"payersUserId": 1,
"paymentDate": 1,
"paymentStatus": 1,
"_id": 1
} }).fetch();
selectedRecipientDetails.forEach((user) => {
payersUserId = user.payersUserId;
paymentDate = user.paymentDate;
paymentStatus = user.paymentStatus;
_id = user._id;
if(paymentStatus === "Failed"){
enableButtonStatusArray.push({
paymentStatus: paymentStatus,
paymentDate: paymentDate,
_id: _id
});
}
else if(paymentStatus === "Passed"){
enableButtonStatusArray.push({
paymentStatus: paymentStatus,
paymentDate: paymentDate,
_id: _id});
}
Session.set('enableButtonStatusArray2', enableButtonStatusArray );
});
var enableButtonStatusArrayForPrint = Session.get('enableButtonStatusArray2');
return enableButtonStatusArrayForPrint;
}
});
Note that the query here lacks a ...{sort: {paymentDate: -1 }} function.
Find below my Router code:
../client/main.js
Router.route('/paymentB2C', {
name: 'paymentB2C',
template: 'paymentB2C',
waitOn: function(){
return Meteor.subscribe('pendingPayments')
}
});
This leads to my Meteor.subscribe('pendingPayments') publish function:
../server/main.js
Meteor.publish('pendingPayments', function pendingPayments(){
return recipientsDetails.find({}, {sort: {paymentDate: -1 }});
});
Note that here is where I have the sort function.
Can someone explain why when codes first runs, the sort is ignored and the the document is randomly sorted, however is sorted out as designed (correctly) after hitting refresh in the browser?
Looking forward to your help.
Ideally, you should sort the data on the client-side query after you subscribe, instead of sorting it in the publish method.
The reason is that if the client subscribes to more than one publish function which will publish data from the same collections, your find query in the client-side will have access to the data from both publish as well as sort won't be effective. Moreover, publish is something which will grant data access to the subscriber and if the mini-mongo on the client side already has the data, it won't sync the data unless new data arrives.
Hence, you should always do sort and filter in your find queries on the client side as well.
Also, I notice that the format of the paymentDate field is not a 'Date'. It should ideally be of the Date format and should look something like ISODate("2019-02-11T02:37:05.000Z") instead of String format "2019-02-11 02:37:05". So if the sorting on the client side is also not working, try saving the paymentDate in the database as Date instead as a String.

Chaining queries in rethinkdb

Lets say I have a "category" table, each category has associated data in the "data" table and it has associated data in other tables "associated" and I want to remove a category with all it's associated data.
What I'm currently doing is something like this:
getAllDataIdsFromCategory()
.then(removeAllAssociated)
.then(handleChanges)
.then(removeDatas)
.then(handleChanges)
.then(removeCategory)
.then(handleChanges);
Is there a way to chain these queries on the db-side?
my functions currently look like this:
var getAllDataIdsFromCategory = () => {
return r
.table('data')
.getAll(categoryId, { index: 'categoryId' })
.pluck('id').map(r.row('id')).run();
}
var removeAllAssociated = (_dataIds: string[]) => {
dataIds = _dataIds;
return r
.table('associated')
.getAll(dataIds, { index: 'dataId' })
.delete()
.run()
}
var removeDatas = () => {
return r
.table('data')
.getAll(dataIds)
.delete()
.run()
}
notice that I cannot use r.expr() or r.do() since I want to do queries based on the result of the previous query.
The problem with my approach is that it won't work for large amounts of "data" since I have to bring all of the ids to the client side, and doing paging for it in the client side in a loop seems like a workaround.
You can use forEach for this:
r.table('data').getAll(categoryID, {index: 'categoryId'})('id').forEach(function(id) {
return r.table('associated').getAll(id, {index: 'dataId'}).delete().merge(
r.table('data').get(id).delete())
});

Resources