How run a multiple predicate mapkeys filter in aerospike nodejs client? - aerospike

In Aerospike, I need run a query based on mapkeys values, filtering by records having 2 values
My predicate for filter by one value looks like this, and it work
predexp.stringValue('t3'),
predexp.stringVar('item'),
predexp.stringEqual(),
predexp.mapBin('category'),
predexp.mapKeyIterateAnd('item')
I tried duplicating the code, using the "and()" method, etc but all tries return error code 4
some help, please?

I'm not entirely sure I understand your question. I think you want to find all records that have a map bin categories that has at least two keys t3 and some other specific value. Correct?
Here is how you would do that:
const as = require('aerospike')
as.connect().then(async client => {
await client.put(new as.Key('test', 'qq', 1), { categories: { red: 1, blue: 2, green: 3 } })
await client.put(new as.Key('test', 'qq', 2), { categories: { blue: 2, green: 3, yellow: 4 } })
const query = client.query('test', 'qq')
query.predexp = [
// Find any record that has a category blue.
as.predexp.stringValue('blue'),
as.predexp.stringVar('cat'),
as.predexp.stringEqual(),
as.predexp.mapBin('categories'),
as.predexp.mapKeyIterateOr('cat'),
// Find any record that has a category yellow.
as.predexp.stringValue('yellow'),
as.predexp.stringVar('cat'),
as.predexp.stringEqual(),
as.predexp.mapBin('categories'),
as.predexp.mapKeyIterateOr('cat'),
// Now combine the two expression using and() to find records with categories blue AND yellow.
// Use or(2) if you want to find records that have categories blue OR yellow.
as.predexp.and(2)
]
// prints [ { green: 3, yellow: 4, blue: 2 } ]
await query.results()
.then(records => records.map(r => r.bins.categories))
.then(console.log)
client.close()
})
Note that I'm using mapKeyIterateOr instead of mapKeyIterateAnd. That's because of each of the two subexpressions, I want any key of the categories map to be blue/yellow. If you use mapKeyIterateAnd that means you want every key of the map to meet your condition.

Related

Get Empty Rows in TypeORM

I'm trying to write a typeORM query which includes multiple where clauses. I am able to achieve this via where option as follows:
const categories = [
{ name: 'master', categoryTypeId: 2, parentId: 1, locationId: null },
{ name: 'food', categoryTypeId: 3, parentId: null, locationId: null }];
const rows = await Repo.find({
where: categories.map((category) => ({
name: category.name,
categoryTypeId: category.categoryTypeId,
locationId: category.locationId
})),
});
I would want to maintain the mapping b/w the input array and the rows returned. For example, I know that the second category doesn't exist in the DB. I would want to have an empty object in the rows variable so that I know which categories didn't yield any result.
Upon research I have found that we can do something with SQL as mentioned here. But, I'm not sure how do I translate into typeORM if I can.

Ramda.js - how to view many values from a nested array

I have this code:
import {compose, view, lensProp, lensIndex, over, map} from "rambda";
let order = {
lineItems:[
{name:"A", total:33},
{name:"B", total:123},
{name:"C", total:777},
]
};
let lineItems = lensProp("lineItems");
let firstLineItem = lensIndex(0);
let total = lensProp("total");
My goal is to get all the totals of all the lineItems (because I want to sum them). I approached the problem incrementally like this:
console.log(view(lineItems, order)); // -> the entire lineItems array
console.log(view(compose(lineItems, firstLineItem), order)); // -> { name: 'A', total: 33 }
console.log(view(compose(lineItems, firstLineItem, total), order)); // -> 33
But I can't figure out the right expression to get back the array of totals
console.log(view(?????, order)); // -> [33,123,777]
That is my question - what goes where the ????? is?
I coded around my ignorance by doing this:
let collector = [];
function collect(t) {
collector.push(t);
}
over(lineItems, map(over(total, collect)), order);
console.log(collector); // -> [33,123,777]
But I'm sure a ramda-native knows how to do this better.
It is possible to achieve this using lenses (traversals), though will likely not be worth the additional complexity.
The idea is that we can use R.traverse with the applicative instance of a Const type as something that is composable with a lens and combines zero or more targets together.
The Const type allows you to wrap up a value that does not change when mapped over (i.e. it remains constant). How do we combine two constant values together to support the applicative ap? We require that the constant values have a monoid instance, meaning they are values that can be combined together and have some value representing an empty instance (e.g. two lists can be concatenated with the empty list being the empty instance, two numbers can be added with zero being the empty instace, etc.)
const Const = x => ({
value: x,
map: function (_) { return this },
ap: other => Const(x.concat(other.value))
})
Next we can create a function that will let us combine the lens targets in different ways, depending on the provided function that wraps the target values in some monoid instance.
const foldMapOf = (theLens, toMonoid) => thing =>
theLens(compose(Const, toMonoid))(thing).value
This function will be used like R.view and R.over, accepting a lens as its first argument and then a function for wrapping the target in an instance of the monoid that will combine the values together. Finally it accepts the thing that you want to drill into with the lens.
Next we'll create a simple helper function that can be used to create our traversal, capturing the monoid type that will be used to aggregate the final target.
const aggregate = empty => traverse(_ => Const(empty))
This is an unfortunate leak where we need to know how the end result will aggregated when composing the traversal, rather than simply knowing that it is something that needs to be traversed. Other languages can make use of static types to infer this information, but no such luck with JS without changing how lenses are defined in Ramda.
Given you mentioned that you would like to sum the targets together, we can create a monoid instance that does exactly that.
const Sum = x => ({
value: x,
concat: other => Sum(x + other.value)
})
This just says that you can wrap two numbers together and when combined, they will produce a new Sum containing the value of adding them together.
We now have everything we need to combine it all together.
const sumItemTotals = order => foldMapOf(
compose(
lensProp('lineItems'),
aggregate(Sum(0)),
lensProp('total')
),
Sum
)(order).value
sumItemTotals({
lineItems: [
{ name: "A", total: 33 },
{ name: "B", total: 123 },
{ name: "C", total: 777 }
]
}) //=> 933
If you just wanted to extract a list instead of summing them directly, we could use the monoid instance for lists instead (e.g. [].concat).
const itemTotals = foldMapOf(
compose(
lensProp('lineItems'),
aggregate([]),
lensProp('total')
),
x => [x]
)
itemTotals({
lineItems: [
{ name: "A", total: 33 },
{ name: "B", total: 123 },
{ name: "C", total: 777 }
]
}) //=> [33, 123, 777]
Based on your comments on the answer from customcommander, I think you can write this fairly simply. I don't know how you receive your schema, but if you can turn the pathway to your lineItems node into an array of strings, then you can write a fairly simple function:
const lineItemTotal = compose (sum, pluck ('total'), path)
let order = {
path: {
to: {
lineItems: [
{name: "A", total: 33},
{name: "B", total: 123},
{name: "C", total: 777},
]
}
}
}
console .log (
lineItemTotal (['path', 'to', 'lineItems'], order)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {compose, sum, pluck, path} = R </script>
You can wrap curry around this and call the resulting function with lineItemTotal (['path', 'to', 'lineItems']) (order), potentially saving the intermediate function for reuse.
Is there a particular reason why you want to use lenses here? Don't get me wrong; lenses are nice but they don't seem to add much value in your case.
Ultimately this is what you try to accomplish (as far as I can tell):
map(prop('total'), order.lineItems)
you can refactor this a little bit with:
const get_total = compose(map(prop('total')), propOr([], 'lineItems'));
get_total(order);
You can use R.pluck to get an array of values from an array of objects:
const order = {"lineItems":[{"name":"A","total":33},{"name":"B","total":123},{"name":"C","total":777}]};
const result = R.pluck('total', order.lineItems);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

Sequelize Querying with Op.or and Op.ne with same array of numbers

I'm having trouble getting the correct query with sequelize.
I have an array representing ids of entries lets say its like this -
userVacationsIds = [1,2,3]
i made the first query like this
Vacation.findAll({
where: {
id: {
[Op.or]: userVacationsIds
}
}
})
.then(vacationSpec => {
Vacation.findAll({
where:{
//Here i need to get all entries that DONT have the ids from the array
}
}
})
I can't get the correct query as specified in my code "comment"
I've tried referring to sequelize documentation but i can't understand how to chain these queries specifically
Also tried an online converter but that failed too.
Specified the code i have above
So i just need some help getting this query correct please.
I eventually expect to get 2 arrays - one containing all entries with the ids from the array, the other containing everything else (as in id is NOT in the array)
I figured it out.
I feel silly.
This is the query that worked
Vacation.findAll({
where: {
id: {
[Op.or]: userVacationsIds
}
}
}).then(vacationSpec => {
Vacation.findAll({
where: {
id: {
[Op.notIn]: userVacationsIds
}
}
})

knex insert multiple rows

I have a problem inserting many rows into postgres db with knex.
I have dynamic number of rows needed to be inserted. The result i expect is:
insert row four times (four is for an example. I dont know exact number of inserts as it comes dynamically from frontend):
field_id will be diffrent in every row: (1,2,3,4) - i have array of these ID's
id_of_product will be always the same
value will be always diffrent: (req.body[id] that comes from Frontend) - ID in brackets is same value as the field_id from an
array
How i can achieve that? I tried looping it with forEach, but it's async operation so i can't use .then() as it will be called four times
Here's what i tried. i dont know how to set field_id and req.body to take it dynamically.
fields = [1,2,3,4]
Expected result:
knex creates 4 inserts as follows:
field_id: 1,
product_id: some static id
value: frontValue[1]
ETC
knex('metadata').insert(
[{ field_id: fields,
product_id: product_id,
value: req.body[fields]
}]
)
If I understand correctly you want to insert 4 records to your metadata table:
{ field_id: 1, product_id: X, value: req.body[1] },
{ field_id: 2, product_id: X, value: req.body[2] },
{ field_id: 3, product_id: X, value: req.body[3] },
{ field_id: 4, product_id: X, value: req.body[4] }
To insert multiple records in the same statement they each need to be separate elements in the array that you supply to Knex (check out the insert docs for additional examples):
const product_id = X;
const fieldsToInsert = fields.map(field =>
({ field_id: field, product_id, value: req.body[field] }));
return knex('metadata').insert(fieldsToInsert)
.then(() => { /* handle success */ })
.catch(() => { /* handle failure */});

Delete and add attributes with array.map and the spread operator

I'm trying to mangle data returned from an api. I've got an array of objects returned. I want to delete the password field and then add a couple of additional fields. I'd like to use the spread operator but my process feels a bit clunky.
myArray.map( item => {
const newItem = { ...item };
delete newItem.password;
newItem.saved = true;
return newItem;
});
Is there a nicer way to do this?
Given an array of objects -
const myArrayOfObjects = [
{id: 1, keyToDelete: 'nonsense'},
{id: 2, keyToDelete: 'rubbish'}
];
Delete the attribute keyToDelete, and add a new key newKey with the value "someVar".
myArrayOfObjects.map(({ keyToDelete, ...item}) => { ...item, newKey:'someVar'});
Updating the array to
[
{id: 1, newKey:'someVar'},
{id: 2, newKey:'someVar'}
]
See this great post for more information on the deletion method.