I am trying to build a query to match two columns and I have tried the following:
obj= obj.filter(e => e.colOne.exactMatch(e.colTwo))
I am not be able to get this working, is there any way to filter by comparing the content of 2 columns?
The filter() method can't dynamically grab the value to filter based on each object, but can be used to filter on a static value.
You can filter a smaller object set (<100K rows) named myUnfilteredObjects of type ObjectType this way:
let myFilteredObjects = new Set<ObjectType>();
for (const unfilteredObj of myUnfilteredObjects) {
if (unfilteredObj.colOne === unfilteredObj.colTwo) {
myFilteredObjects.add(unfilteredObj);
}
}
Edit: updating with a solution for larger-scale object sets:
You can create a new boolean column in your object's underlying dataset that is true if colOne and colTwo match, and false otherwise. Filtering on this new column via the filter() method will then work as you expect.
It is not possible to compare two columns when writing Functions. A recommended strategy here would be to create a new column that captures your equality. For example in your pyspark pipeline, right before you generate the end objects that get indexed:
df.withColumn("colOneEqualsColTwo", F.when(
F.col("colOne") == F.col("colTwo"), True
).otherwise(False)
And then filter on that new column:
obj = obj.filter(e => e.colOneEqualsColTwo.exactMatch(true))
Related
I am using MYSQL through Sequelize to build a node.js application with typescript. I created a table and the table has a field which I made a JSON dataType and made it an array by default. I have been able to push items into the array. I would like to remove items from the array, how can I achieve this?
I tried using await category.update({array_Of_food:Sequelize.fn('array_remove',Sequelize.col('array_of_food'),JSON.stringify(category.dataValues.array_Of_food && category.dataValues.array_Of_food[index]))})
I got an error that array_remove does not exist.
I solved my problem this way since I couldn't find an inbuilt way of doing it. I know this is not the best method but at least it works. At the end, I wrote a longer code.
1.Get the string value of the item you want to remove.
const indexString = food.dataValues.food_Name as string;
2.Get the index number of that item inside the array you wish to delete it from:
const index = category.dataValues.array_Of_food?.indexOf(indexString) as number;
3.Create a variable for the the array out of the model colum that you are targeting.
const arrayValue = category.dataValues.array_Of_food
4.Remove that item from the array variable that you crceated:
arrayValue?.splice(index, 1);
5.Use the update method and pass the array variable you deleted the item from as the update: This will replace the initial array values with the new array values. Remember that the new array values contain all the values in the array column excluding the value you deleted.
await category.update({array_Of_food: arrayValue})
This worked!
I have a PostgreSQL table that stores some information in a JSON column, I'd like to take the data from this JSON column and populate a secondary table in the BIRT report.
I've got the data into a JSON object just fine, I can use it, but table #2 won't populate any data even though there is data in the JSON object.
DataSource1 it attached to DataSet1 which is PostgreSQL. DataSource2 is a scripted DS, and it has Dataset2 attached to it with columns defined.
In dataset1 I have the OnFetch function making my JSON array:
vars["invoiceData"] = JSON.parse(row["i_invoice"]);
Then I have in dataset2 (json dataset) I have this for the fetch event setup:
// Get the length of the object
len = vars["invoiceData"].labor.length;
count = 0;// Counter used to step through each item in the JSON object.
// Loop through the JSON object adding it to the scripted data source
if(count < len && len != 0) {
row["hrs"] = vars["invoiceData"].labor[count].hrs;
row["desc"] = vars["invoiceData"].labor[count].desc;
row["rate"] = vars["invoiceData"].labor[count].rate;
row["amount"] = vars["invoiceData"].labor[count].amount;
count++;
return true;
}
return false;
If I echo out the length of my array it has one row in it, but that table never comes back with anything, always empty on my report.
You are mixing initialization code with loop code.
Just think about this fragment:
count = 0;
if (...) {
count++;
return true;
}
return false;
You need to split and modify this code. Basically, for a scripted data set you need three things:
A counter variable (or something similar). This is best declared as a report variable.
Initialization of the counter variable in the data set's open event.
Using the counter variable in the data set's fetch event, eg modifying it and comparing it to the data length.
Your code will return the first data row in an endless loop, because what BIRT does is:
open()
while fetch():
emit the current row
Thus, your code is definitely wrong.
OTOH the behavior that you describe doesn't match what I would expect: A never-ending report. So there are probably other errors in your report. What does the "problems" view in the BIRT designer show?
is there anyway to make a query in MongoDB using a JSON and returning a object if one field of the json matches with some in the database?
for example, I have the this object called keysArray
{ house: 'true', garden: 'false' }
and I would like to make a query in Mongo passing this object as a query field and return if some object in my database matches with at least one of those fields :
keysArray.forEach(function(key){
collection.find({keysArray}, function(err, propertyMatch){
console.log(propertyMatch)
})
})
I got no objects back, even if I have one object in my database that matches these fields.
Thanks in advance
...and I would like to make a query in Mongo passing this object as a
query field and return if some object in my database matches with at
least one of those fields.
It sounds like OR logic - if I understood it well.
On this specific case it's not possible to pass in JSON-like object to query as it would be a implicit AND logic condition.
So you should build first a OR expression and use it in collection.find(), something like this:
var myjson = {'status': 32, 'profile': {$exists: false}};
function build_logic_or(json) {
var orExpr = [];
for (var field in json) {
var expr = {};
expr[field] = json[field];
orExpr.push(expr);
}
return {'$or': orExpr};
}
It would build an expression like this:
{"$or":[{"status":32},{"profile":{"$exists":false}}]}
So:
db.collection.find(build_logic_or(myjson))
I have a select that I get Json post with http, but I try to sets initially selected index but there is nothing in the list do not select anything. because the json is great.
public AppMainScreen() {
loadLists();
MySelect = new ObjectChoiceField( "Select: ", new Object[0], 3 );
VerticalFieldManager vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL);
vfm.add(MySelect);
add(vfm);
}
This statement appears wrong to me:
new ObjectChoiceField( "Select: ", new Object[0],3);
The second parameter to this constructor is supposed to be an array of objects whose .toString() method will be used to populate the choices. In this case, you have given it a 0 length array, i.e. no Objects. So there is nothing to choose. And then you have asked it to automatically select the 3rd item, and of course there is no 3rd item.
You should correct the code to actually supply an object array.
One option to make it easy is have your JSON load actually create a String array with one entry per selectable item. Then you use the index selected to identify the chosen item.
At the beginning of a method I want to check if the method is called with these exact parameters before, and if so, return the result that was returned back then.
At first, with one parameter, I used a Dictionary, but now I need to check 3 parameters (a String, an Object and a boolean).
I tried making a custom Object like so:
var cacheKey:Object = { identifier:identifier, type:type, someBoolean:someBoolean };
//if key already exists, return it (not working)
if (resultCache[cacheKey]) return resultCache[cacheKey];
//else: create result ...
//and save it in the cache
resultCache[cacheKey] = result;
But this doesn't work, because the seccond time the function is called, the new cacheKey is not the same object as the first, even though it's properties are the same.
So my question is: is there a datatype that will check the properties of the object used as key for a matching key?
And what else is my best option? Create a cache for the keys as well? :/
Note there are two aspects to the technical solution: equality comparison and indexing.
The Cliff Notes version:
It's easy to do custom equality comparison
In order to perform indexing, you need to know more than whether one object is equal to another -- you need to know which is object is "bigger" than the other.
If all of your properties are primitives you should squash them into a single string and use an Object to keep track of them (NOT a Dictionary).
If you need to compare some of the individual properties for reference equality you're going to have a write a function to determine which set of properties is bigger than the other, and then make your own collection class that uses the output of the comparison function to implement its own a binary search tree based indexing.
If the number of unique sets of arguments is in the several hundreds or less AND you do need reference comparison for your Object argument, just use an Array and the some method to do a naive comparison to all cached keys. Only you know how expensive your actual method is, so it's up to you to decide what lookup cost (which depends on the number of unique arguments provided to the function) is acceptable.
Equality comparison
To address equality comparison it is easy enough to write some code to compare objects for the values of their properties, rather than for reference equality. The following function enforces strict set comparison, so that both objects must contain exactly the same properties (no additional properties on either object allowed) with the same values:
public static propsEqual(obj1:Object, obj2:Object):Boolean {
for(key1:* in obj1) {
if(obj2[key1] === undefined)
return false;
if(obj2[key1] != obj2[key1])
return false;
}
for(key2:* in obj2)
if(obj1[key2] === undefined)
return false;
return true;
}
You could speed it up by eliminating the second for loop with the tradeoff that {A:1, B:2} will be deemed equal to {A:1, B:2, C:'An extra property'}.
Indexing
The problem with this in your case is that you lose the indexing that a Dictionary provides for reference equality or that an Object provides for string keys. You would have to compare each new set of function arguments to the entire list of previously seen arguments, such as using Array.some. I use the field currentArgs and the method to avoid generating a new closure every time.
private var cachedArgs:Array = [];
private var currentArgs:Object;
function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
currentArgs = { stringArg:stringArg, objArg:objArg, boolArg:boolArg };
var iveSeenThisBefore:Boolean = cachedArgs.some(compareToCurrent);
if(!iveSeenThisBefore)
cachedArgs.push(currentArgs);
}
function compareToCurrent(obj:Object):Boolean {
return someUtil.propsEqual(obj, currentArgs);
}
This means comparison will be O(n) time, where n is the ever increasing number of unique sets of function arguments.
If all the arguments to your function are primitive, see the very similar question In AS3, where do you draw the line between Dictionary and ArrayCollection?. The title doesn't sound very similar but the solution in the accepted answer (yes I wrote it) addresses the exact same techinical issue -- using multiple primitive values as a single compound key. The basic gist in your case would be:
private var cachedArgs:Object = {};
function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
var argKey:String = stringArg + objArg.toString() + (boolArg ? 'T' : 'F');
if(cachedArgs[argKey] === undefined)
cachedArgs[argKey] = _yourMethod(stringArg, objArg, boolArg);
return cachedArgs[argKey];
}
private function _yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
// Do stuff
return something;
}
If you really need to determine which reference is "bigger" than another (as the Dictionary does internally) you're going to have to wade into some ugly stuff, since Adobe has not yet provided any API to retrieve the "value" / "address" of a reference. The best thing I've found so far is this interesting hack: How can I get an instance's "memory location" in ActionScript?. Without doing a bunch of performance tests I don't know if using this hack to compare references will kill the advantages gained by binary search tree indexnig. Naturally it would depend on the number of keys.