Search TinCan Verbs - javascript

Is it possible to filter/search for verbs containing some text in the ID using TinCan?
I.e. below I want to find all verbs that start with a particular ID in the URL?
Or do I have to download all of them and filter?
lrs.queryStatements(
{
params: {
verb: new TinCan.Verb(
{
id: "http://example.com/g*"
}
),
since: "2016-01-05T08:34:16Z"
},
callback: function (err, sr) {
if (err !== null) {
console.log("Failed to query statements: " + err);
// TODO: do something with error, didn't get statements
return;
}
if (sr.more !== null) {
// TODO: additional page(s) of statements should be fetched
}
console.log('query complete');
console.log(sr);
// TODO: do something with statements in sr.statements
}
}
);

It isn't possible from the LRS' /statements resource. That resource was never intended as a full query interface and the LRS isn't intended to be searched for direct reporting purposes. It should be thought of more as a stream of data with limited filter capabilities to allow the stream to be manageable for specific long term use cases. So you can "filter" the stream on a specific single identifier, but you can't "search" the statements.

Related

Approach to selecting a document

I am using Couchbase in a node app. Every time I insert a document, I am using a random UUID.
It inserts fine and I could retrieve data based on this id.
But in reality, I actually want to search by a key called url in the document. To be able to get or update or delete a document.
I could possibly add the url as the id I suppose but that is not what I see in any database concepts. Ids are not urls
or any unique names. They are typically random numbers or incremental numbers.
How could I approach this so that I can use a random UUID as id but be able to search by url?
Cos lets say the id was 56475-asdf-7856, I am not going to know this value to search for right.
Whereas if the id was https://www.example.com I know about this url and searching for it would give me what I want.
Is it a good idea making the url the id.
This is in a node app using Couchbase.
databaseRouter.put('/update/:id', (req, res) => {
updateDocument(req)
.then(({ document, error }) => {
if (error) {
res.status(404).send(error);
}
res.json(document);
})
.catch(error => res.status(500).send(error));
});
export const updateDocument = async (req) => {
try {
const result = await collection.get(req.params.id); // Feels like id should be the way to do this, but doesn't make sense cos I won't know the id beforehand.
document.url = req.body.url || document.url;
await collection.replace(req.params.id, document);
return { document };
} catch (error) {
return { error };
}
};
I think it's okay to use URLs as IDs, especially if that's the primary way you're going to lookup documents, and you don't need to change the URL later. Yes, often times IDs are numbers or UUIDs, but there is no reason you have to be restricted to this.
However, another approach you can take is to use a SQL query (SQL++, technically, since this is a JSON database).
Something like:
SELECT d.*
FROM mybucket.myscope.mydocuments d
WHERE d.url = 'http://example.com/foo/baz/bar'
You'll also need an index with that, something like:
CREATE INDEX ix_url ON mybucket.myscope.mydocuments (url)
I'd recommend checking out the docs for writing a SQL++ query (sometimes still known as "N1QL") with Node.js: https://docs.couchbase.com/nodejs-sdk/current/howtos/n1ql-queries-with-sdk.html
Here's the first example in the docs:
async function queryPlaceholders() {
const query = `
SELECT airportname, city FROM \`travel-sample\`.inventory.airport
WHERE city=$1
`;
const options = { parameters: ['San Jose'] }
try {
let result = await cluster.query(query, options)
console.log("Result:", result)
return result
} catch (error) {
console.error('Query failed: ', error)
}
}

Using Lambda with Nodejs Count Some queries in Dynamo DB

After using the below to pull data from Dynamo db sucessfully
async function pullone(sessionid) {
const params = {
TableName: dynamodbTableName,
Key: {
'sessionid': sessionid
}
};
return await dynamodb.get(params).promise().then((response) => {
return response.Item
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
});
}
Instead of 'return response.Item' i just want to return the count instead.
I tried doing count(pullone(sessionid)) but not sure if that is even a valid method. Please assist
Not sure if I understood your question, but:
Since you're requesting data associated with a primary key, you'll get either 0 or 1 element in Item.
So, if you aim to know if "you've found something or not", you can use Number(response.Item != null) and you'll get 1 in case of "something" and 0 in case of "nothing".
If, instead, your data contains a "count" attribute, then (await pullone(sessionId)).count should work.
Otherwise, you have to query your DB (but you'll get Items (plural) in your response) and use the length() function of the Items array you'll get in the response.

(MongoDB) Data submitted from user A is being sent into User B's document

https://imgur.com/a/giK2bSt
I'm finding and updating the current user's document in the db using:
Player.findOneAndUpdate(
player.discordID (example below), but it ignores the discordID query and inputs the data into the wrong document. I logged the currrent user's discordID in the terminal to make sure it is fetching the current user's and it is.
if (
// if user submitted data matches the gamertags and platforms listed in-
// their call of duty account, execute assignRoleNow
(loggedIn =
true &&
checkTag == true &&
checkPlat == true)
) {
console.log(player.discordID);
console.log(player);
Player.findOneAndUpdate(
player.discordID,
{
$set: {
platform: platform,
gamertag: gamertag,
},
},
function callback(err, doc) {
if (err) {
// Show errors
console.log(err);
}
}
);
The query portion of you findOneAndUpdate may not be in the correct format. Remember, it should look the same as a find for the Player so it may need to be:
{discordId: player.discordID}
instead of just:
player.discordID

How to query LRS by agent via javascript

I feel like I've tried everything, but I keep coming up short. I am working on a course in Storyline 360, and I am able to return statements just fine when using verbs and object IDs, but no matter what I do to try and return statements for a specific Agent, I cannot get a query to go through.
Here's my code as it stands now - where I do return plenty of statements...what I need to know is how to have it query the current learner's statements for matches. I'm able to pull in their name or mbox, but trying to pass those through in my params fails on me every time.
Any help is very much appreciated!
var lrs;
var statementFound = false;
var player = GetPlayer();
try {
lrs = new TinCan.LRS(
{
endpoint: "https://cloud.scorm.com/lrs/MYINFO/",
username: "MYINFO",
password: "MYINFO",
allowFail: false
}
);
}
catch (ex) {
console.log("Failed to setup LRS object: ", ex);
// TODO: do something with error, can't communicate with LRS
};
var myObj = JSON.parse(getParameterByName('actor'));
lrs.queryStatements(
{
params: {
verb: new TinCan.Verb(
{
id: "http://adlnet.gov/expapi/verbs/answered"
}
)
},
callback: function (err, sr) {
if (err !== null) {
console.log("Failed to query statements: " + err);
// TODO: do something with error, didn't get statements
return;
}
if (sr.more !== null) {
// TODO: additional page(s) of statements should be fetched
}
if (sr.statements.length > 0) {
statementFound = true;
console.log(sr.statements);
player.SetVar("sf",statementFound);
}
}
}
);
var myObj is able to pull in the necessary info to ID the learner if needed - but again, I just can't figure out how to get it passed in the query.
You need to set an agent property in the params object passed in the first argument. Assuming the Agent is the actor in statements.
lrs.queryStatements(
{
params: {
agent: TinCan.Agent.fromJSON(getParameterByName('actor'))
}
},
...
);

Meteor. Prevent multiple inserts from console

Let's imagine I'm a bad man, and I see that website uses Meteor.
I search for a collection description in js files (let it be "Posts"), and write in console
for (var i = 0; i < 10000000000; i++) {
Posts.insert({title:'foobar'});
}
And we got the DB full of trash.
How to prevent this? Registration isn't much problem for such attack, I suppose.
Use the allow rules.
First remove the insecure package:
meteor remove insecure
Then make some rules (e.g you have to be logged in) & in the example below you can only modify your own documents.
Server side code
Posts.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return (userId && doc.owner === userId);
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return doc.owner === userId;
},
remove: function (userId, doc) {
// can only remove your own documents
return doc.owner === userId;
}
});

Categories