In RethinkDB I am trying to chain multiple queries to multiple database tables. The idea is the same as stored procs for traditional dB's. Basically I query all the users connected to a device and then for each users try to get the rules attached from a rules table.
Here is a gist of the ReQL query I am writing. But forEach does not work as it wants a write query and not read and also do() is failing. Any suggestions?
const get_distance = function(location){
const final_location = 500;
return r.expr(500).sub(location);
};
const run_rule = function(device,distance){
return r.db('locationtracker_development').table('customer_details').filter(function(cust){
return cust("deviceId").contains(device);
}).pluck("userId").forEach(function(userName){
//TODO Work on each user
return r.db('locationtracker_development').table('user_rules').filter({'userId':userName('userId')});
});
};
r.do(get_distance(100)).do(function(dist){
return run_rule('gXtzAawbc6',dist);
});
I have gotten it resolved with help from the Slack Channel of RethinkDB.
Here is the code :
const get_distance = function(location){
const final_location = 500;
return r.expr(500).sub(location);
};
const run_rule = function(device,distance){
return r.db('locationtracker_development').table('customer_details').filter(function(cust){
return cust("deviceId").contains(device);
}).coerceTo('array').map(function(doc){
return doc('userId');
}).do(function(userIds){
//return userIds;
return r.db('locationtracker_development').table('user_rules').
getAll(r.args(userIds),{index:'userId'});
});
};
r.do(get_distance(100)).do(function(dist){
return run_rule('gXtzAawbc6',dist);
});
Basically the objects returned needs to be coercedTo and Array and then using map and do functionality we can achieve querying multiple DBs.
Related
I am fairly new to Apollo and Graphql and I quite don't know what I am doing wrong. I will try to explain my problem with some simplified code but if I am missing some information please let me know and I will update it.
I have an Apollo client instance consuming an external (Directus CMS) graphql API not modifiable by me.
The thing is I am querying a paginated (infinite scroll) of posts with offset and limit variables and the data returned is correct. I am using the following typePolicy in order to merge results arrays in my inMemoryCache. This code is from an example in the Apollo Docs:
posts {
const merged = existing ? existing.slice(0) : [];
const postIdToIndex = Object.create(null);
if (existing) {
existing.forEach((post, index) => {
postIdToIndex[readField("id", post)] = index;
});
}
incoming.forEach((post) => {
const id = readField("id", post);
const index = postIdToIndex[id];
if (typeof index === "number") {
// Merge the new post data with the existing post data.
merged[index] = mergeObjects(merged[index], post);
} else {
// First time we've seen this post in this array.
postIdToIndex[id] = merged.length;
merged.push(post);
}
});
return merged;
}
and this is a simplified version of my query:
query($offset: Int $limit: Int) {
posts(limit: $limit offset: $offset) {
id
name
}
}
With this merge function and query I get my pagination right and everything loads correctly. But when I try to query a single instance of post that queries also additional fields from it with the following query:
query($offset: Int $limit: Int $post_id: Int) {
posts(filter:{id:{_eq: $post_id}}) {
id
name
other_data
}
}
This returns undefined constantly when using useQuery() although i can see that is coming through my merge funtion and merging objects with the mergeObjects() function. If I use a fetchPolicy of no-cache in this query, the data returns correctly so it has something to do with the cache.
I hope someone can lead me in the right direction so I can fix this problem.
Thank you everyone in advance!!
Goal: use Google App Script to get {link:url} and {driveFile:alternativeLink} from student submissions (attachments) to a Google Classroom Assignment.
Issue: While I can get all of the attachments, I cannot filter down to the specific type of attachment or it's respected property. Specific types of attachments return 'undefined'. Any help would be greatly appreciated.
I can get the the desired results using the Classroom API website by adding to the "field" input:
studentSubmissions.assignmentSubmission.attachments.driveFile
https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions/liststrong text
function testStudSubs(){
console.log(getStudSubs());
}
function getStudSubs(){
const COURSE_ID = "60005382479";
const COURSE_WORK_ID = "141252225149";
const USR_ID = {userId:"105308051639096321984"};
const ID = "Cg0IhMWczB0Q_dCnmo4E";
const submissions = Classroom.Courses.CourseWork.StudentSubmissions.list(COURSE_ID, COURSE_WORK_ID, USR_ID).studentSubmissions
return submissions.map(submission => {
return `${submission.assignmentSubmission.attachments}`
});
}
Answer: (Special thanks to Yagisanatode.com for pointing me in the correct direction.)
1st: ensure proper scopes have been added...see response from Sourabh Choraia stackOverflow response. The scopes will ensure we have access to the objects. Once we request a specific object (ex: link or driveFile), attachments that are not of that object type will display as undefined.
2nd: we need to remove the undefined objects. To do this, we can following w3resource (javascript version), adding the format to our "test" function (w3resource example).
We also need to tweak the array by flattening it. Flattening the array will show the correct length by including the undefined objects.
Finally, for the result, we will map it and pull the desired property (Google Api - Student Submissions List).
Here is working example:
function testStudSubs(){
console.log(getStudSubs());
console.log(getStudSubs().length);
console.log(getStudSubs().flat(2)); // creates separate object for each...ex: 4
const myFlat = getStudSubs().flat(2);
let index = -1;
const arr_length = myFlat ? myFlat.length : 0;
let resIndex = -1;
const result = [];
while (++index < arr_length) {
const value = myFlat[index];
if (value) {
result[++resIndex] = value;
}
}
console.log(result.map(result => { return result.alternateLink + `:` + result.title}));
return result.map(result => { return result.alternateLink + `:` + result.title});
}
/*/////////////////////////////
/
/ Pulls student submitted work from Classroom
/
*//////////////////////////////
function getStudSubs(){
const COURSE_ID = "60005382479"; // update
const COURSE_WORK_ID = "141252225149"; //update
const USR_ID = {userId:"105308051639096321984"}; //update
const submissions = Classroom.Courses.CourseWork.StudentSubmissions.list(COURSE_ID, COURSE_WORK_ID, USR_ID).studentSubmissions
return submissions.map(submission => {
return submission.assignmentSubmission.attachments.map(attachments =>
{
return attachments.driveFile
});
});
return submissions
}
Is there a way in JXA to get multiple properties from multiple objects with a single call?
For example, I want to get name and enabled property from menu items which can be done for each individual property as follows:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.name()
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.enabled()
but is it possible to get them with a single function call? Something like:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.select('name', 'enabled')
I know, that I can iterate through the menuBarItems and collect properties from .properties() method, but this approach is too slow, that's why I'm looking for other options.
UPDATE
I'm looking for better performance, not for nicer syntax, i.e. I want properties to be retrieved in a single call to System Events.
I'd probably do it like this:
sys = Application('com.apple.systemevents');
FinderProc = sys.processes['Finder'];
FinderMenuBarItems = FinderProc.menuBars[0].menuBarItems();
Array.from(FinderMenuBarItems,x=>[x.name(),x.enabled()]);
By first converting the object to an array, this allows one to map each element and retrieve the desired properties for all in one go. The code is split over several lines for ease of reading.
EDIT: added on 2019-07-27
Following on from your comment regarding Objective-C implementation, I had a bit of time today to write a JSObjc script. It does the same thing as the vanilla JXA version above, and, yes, it clearly makes multiple function calls, which is necessary. But it's performing these functions at a lower level than System Events (which isn't involved at all here), so hopefully you'll find it more performant.
ObjC.import('ApplicationServices');
ObjC.import('CoreFoundation');
ObjC.import('Foundation');
ObjC.import('AppKit');
var err = {
'-25211':'APIDisabled',
'-25206':'ActionUnsupported',
'-25205':'AttributeUnsupported',
'-25204':'CannotComplete',
'-25200':'Failure',
'-25201':'IllegalArgument',
'-25202':'InvalidUIElement',
'-25203':'InvalidUIElementObserver',
'-25212':'NoValue',
'-25214':'NotEnoughPrecision',
'-25208':'NotImplemented',
'-25209':'NotificationAlreadyRegistered',
'-25210':'NotificationNotRegistered',
'-25207':'NotificationUnsupported',
'-25213':'ParameterizedAttributeUnsupported',
'0':'Success'
};
var unwrap = ObjC.deepUnwrap.bind(ObjC);
var bind = ObjC.bindFunction.bind(ObjC);
bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
return unwrap($.CFMakeCollectable(this[0]));
}
function getAttrValue(AXUIElement, AXAttrName) {
var e;
var _AXAttrValue = Ref();
e = $.AXUIElementCopyAttributeValue(AXUIElement,
AXAttrName,
_AXAttrValue);
if (err[e]!='Success') return err[e];
return _AXAttrValue.nsObject();
}
function getAttrValues(AXUIElement, AXAttrNames){
var e;
var _AXAttrValues = Ref();
e = $.AXUIElementCopyMultipleAttributeValues(AXUIElement,
AXAttrNames,
0,
_AXAttrValues);
if (err[e]!='Success') return err[e];
return _AXAttrValues.nsObject();
}
function getAttrNames(AXUIElement) {
var e;
var _AXAttrNames = Ref();
e = $.AXUIElementCopyAttributeNames(AXUIElement, _AXAttrNames);
if (err[e]!='Success') return err[e];
return _AXAttrNames.nsObject();
}
(() => {
const pid_1 = $.NSWorkspace.sharedWorkspace
.frontmostApplication
.processIdentifier;
const appElement = $.AXUIElementCreateApplication(pid_1);
const menuBar = getAttrValue(appElement,"AXMenuBar");
const menuBarItems = getAttrValue(menuBar, "AXChildren");
return menuBarItems.map(x => {
return getAttrValues(x, ["AXTitle", "AXEnabled"]);
});
})();
In the code following this description, I am trying to find and remove all these bad ListConfig objects that didn't have a group object set. It is correctly finding them, however it does not remove them. Is there something I am missing in the following code?
var Groups = [];
function queryForGroups(callback) {
var Group = Parse.Object.extend("Group");
var query = new Parse.Query(Group);
query.limit(1000);
query.find().then(function(result) {
Groups = result;
callback();
});
};
function removeConfigs(){
var Config = Parse.Object.extend("ListConfig");
var query = new Parse.Query(Config);
query.limit(10000);
query.notContainedIn("group", Groups);
query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
queryForGroups(function() {
removeConfigs();
});
};
removeBadConfigs();
The code could be a little cleaner with respect to mixing promises, callbacks and an unnecessary global. Beyond that, it looks like it should work as long as your data model supports it. Specifically, your ListConfig object must have a "group" property, and it must have a Parse.Object value set for that property. The most common error I've seen is something like this:
var myGroup = // a parse object of type Group
myListConfig.set("group", myGroup.id); // WRONG
myListConfig.set("group", myGroup); // RIGHT
Assuming you've got that right, then it's mysterious why you're not seeing some deletes, but here's the code cleaned up with promises...
function queryForGroups() {
let query = new Parse.Query("Group")
query.limit(1000);
return query.find();
};
function removeConfigsWithGroups(groups){
let query = new Parse.Query("Config");
query.notContainedIn("group", groups);
return query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
return queryForGroups(function(groups) {
return removeConfigsWithGroups(groups);
});
};
removeBadConfigs();
I figured it out. I removed "useMasterKey: true" because 1) it isn't needed for objects not with elevated privileges and 2) I was not running it in Cloud Code.
is it possible to use the replication filter feature of couchdb (http://wiki.apache.org/couchdb/Replication#Filtered_Replication) by requesting a view, f.e.:
.../_view/candidates?filter=hrtool/myfilter
This would be nice to filter the documents based on the usersession or userrole
Thanks in advance
fadh
That is possible with a _list function.
List functions are Javascript code which pre-process the view output before sending it to the client. You can modify the view output in any way, such as by filtering some rows.
function(head, req) {
// lists.filtered: filter view output by using a replication filter.
var ddoc = this; // A common trick to explicitly identify the design document.
function error(reason) {
start({"code":400, "headers":{"content-type":"application/json"}});
send(JSON.stringify({"error":reason}));
}
var filter_name = req.query.filter;
if(!filter_name)
return error("Need filter_name parameter");
var filter_src = ddoc.filters[filter_name];
if(!filter_src)
return error("Invalid filter_name: " + filter_name);
// Not 100% sure on this, you could also use new Function(args, src);
// In the worst-case, the couchapp tool has the !code tool to copy code.
var filter = eval(filter_src); // Not 100% sure on this
var row;
start({"headers":{"content-type":"application/json"}});
send('{"rows":[\r\n');
var first = true;
while(row = getRow()) {
if(filter(row)) { // Or perhaps use include_docs=true and filter(row.doc)
if(! first)
send(",\r\n");
first = false;
send(JSON.stringify(row));
}
}
send("]}\r\n");
}
Use this list "filter" like any filter function:
GET /db/_design/example/_list/filtered/candidates?filter=myfilter&include_docs=true