We need to update the all the documents in a collection to change their shape. We'd like to record an audit of the change in a different collection where we will store a document which contains the old and new version. In order to make this change atomic, we are using a stored proc.
The issue we are facing is updating another collection from a stored proc. It seems the audit document is always written into the collection the stored proc belongs to.
I have written up a sample stored proc:
function sample(prefix) {
var context = getContext();
var fooCollection = context.getCollection();
var barCollection = context.getCollection("BarCollection");
// Query documents and take 1st item.
var isAccepted = fooCollection.queryDocuments(
fooCollection.getSelfLink(),
'SELECT * FROM root r',
function (err, feed, options) {
if (err) throw err;
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
if (!feed || !feed.length) context.getResponse().setBody('no docs found');
else {
var fooDoc = feed[0];
var barDoc = {
"foo" : fooDoc,
"bar" : "bar"
}
var isAccepted2 = barCollection.createDocument(barCollection.getSelfLink(), barDoc);
if (!isAccepted2) throw new Error('The query was not accepted by the server.');
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
In this sample, my stored proc is saved in the FooCollection. I get a document and try to save a copy into the BarCollection. The new document is always saved into the FooCollection.
Is this scenario supported in Document DB? If so, what changes do I need to make the stored proc to make it work?
DocumentDB stored procedures are collection-scoped. You will not be able to write audit info to a separate collection; you'd need to write to the same collection.
Related
I tried to create a stored procedure using the sample sp creation code from Azure docs, but i couldn't fetch the collection details. It always returns null.
Stored Procedure
// SAMPLE STORED PROCEDURE
function sample(prefix) {
var collection = getContext().getCollection();
console.log(JSON.stringify(collection));
// Query documents and take 1st item.
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT * FROM root r',
function (err, feed, options) {
if (err) throw err;
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var body = { prefix: prefix, feed: feed[0] };
response.setBody(JSON.stringify(body));
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
The console shows only this.
the results shows no doc found because of not getting collection.I have passed the partition key at time of execution via explorer.
I had a similar issue. I think the Azure portal doesn't execute stored procedures properly when the partition key is not a string.
In my case I had a partitionKey that is a number. When I executed the stored procedure via the portal I always got an empty resultSet, even though I had documents in my database. When I changed the structure a little, and made my partitionKey a string, the stored procedure worked fine.
Did you create the ToDoList Database with the Items Collection? Yo can do this from the Quick start blade in the Azure portal.
And then create an SP to run against that collection. There is no partition key required, so no additional params are required (leave blank).
The Collection is created without any documents. You may choose to add documents via the Query Explorer blade or via the sample ToDoList App that is available via the Quick start blade.
You are debugging in a wrong way.
It is perfectly fine to see "{\"spatial\":{}}" in your console log, even if the collection has items. Why? well because that is a property of that object.
So regarding what you said:
the results shows no doc found because of not getting collection
is false. I have the same console log text, but I have items in my collection.
I have 2 scenarios for why your stored procedure return no items:
I had the same issue trying on azure portal UI(in browser) and for my surprise I had to insert an item without the KEY in order that my stored procedure to see it.
On code you specify the partition as a string ie. new PartitionKey("/UserId") instead of your object ie. new PartitionKey(stock.UserId)
When I try to call Dexie on a database on which another call has been done by IndexedDB, there rises an error that the connection is already made to the database.
Can we pass an existing connection to Indexedb to Dexie?
This can be helpful when we want to use same connection in a Dexie object and another object and this happens to me when I try to add Dexie to my project. I don't want to rewrite the existing function.
Example:
function initDataBase(callback){
if(window.indexedDB){
var requeteBDD = window.indexedDB.open("databasename",1);
requeteBDD.onsuccess = function(){
if(typeof callback == "function")
callback(requeteBDD.result);
};
}
}
So can we do,for instance
initDataBase(function(db){
var dex = new Dexie(db);
});
I would like to use same connection as the first one.
Is it possible?
It's not possible as of current version to pass an instance of IDBDatabase into Dexie constructor. However, this would definitely be an easy pull request to do in the source, as Dexie already has the ability to open existing database by name and adapt to it's existing schema.
However, you should not get an error if you instanciate multiple IDBDatabases to same database name unless one of them tries to upgrade it using another version.
Dexie can open an existing database without creating the schema (even though you can only pass a name and not the db instance), as shown in the following fiddle: https://jsfiddle.net/dfahlander/b8Levamm/
new Dexie('MyDatabase').open().then(function (db) {
log ("Found database: " + db.name);
log ("Database version: " + db.verno);
db.tables.forEach(function (table) {
log ("Found table: " + table.name);
log ("Table Schema: " +
JSON.stringify(table.schema, null, 4));
});
}).catch('NoSuchDatabaseError', function(e) {
// Database with that name did not exist
log ("Database not found");
}).catch(function (e) {
log ("Oh uh: " + e);
});
(which fails because the given DB is not there. But if you create it on jsfiddle and run it again, you'll see it open).
I send a query from Node.js to Neo4j, but I do not see anything callback. The query is correctly executed but I am unable to see any information i nthe callback and log it in the console.
I think node.js executes console.log before any data has come, but I do not know how to solve it.
Node.js:
// Load Modules
var neo4j = require('neo4j');
// Database Connection
var db = new neo4j.GraphDatabase("http://neo4j:Gemitis26#localhost:7474/");
// Inizialize Query
var query = "CREATE (:Song {name:'James'})";
db.cypher(query, function(err, node){
if(err) throw err;
// Output node properties.
console.log(node.data);
// Output node id.
console.log(node._id);
});
Output:
C:\Users\RRamos\Documents\Projects\test-neo4j>node index.js
[]
undefined
As I said, I check it and it is correctly created.
There are a number of problems in your code:
Your Cypher query does not have a RETURN clause so your query response will always be an empty array (because it will never contain any result rows).
Your callback is expecting to wrong data structure for the response.
Try this code. It dumps out the error (if any) and the response, so that you can see the actual data structure of a response. It also uses a for-loop to iterate through the rows of data in the response and print out each s node's properties and its native ID. In your case, there will only be at most one result row, so the loop is not strictly necessary, but in general there can be multiple rows.
// Load Modules
var neo4j = require('neo4j');
// Database Connection
var db = new neo4j.GraphDatabase("http://neo4j:Gemitis2#localhost:7474/");
// Inizialize Query
var query = "MATCH (s:Song {name:'James'}) RETURN s";
db.cypher(query, function(err, res){
// Dump out the err and response, to see the data structure.
console.log("err: %j, res: %j", err, res);
if(err) throw err;
// Print out the data for each row in the response.
for (var i = 0; i < res.length; i++) {
var s = res[i].s;
// Output node properties.
console.log(s.properties);
// Output node id.
console.log(s._id);
}
});
Is it possible to setup a web hook for anytime a push notification is sent via Parse?
I want to retrieve the details of the push notification and set a column against any devices the push notification was sent to
No hook that I'm aware of, but you could run all of your pushes through one place in your code (either client or a cloud function), and do whatever post-push work you want to do there. Presuming JS and advanced targeting, it could look like this:
function pushToInstallations(query, data) {
var params = { where: query, data: data};
return Parse.Push.send(params).then(function() {
// this is the interesting part, run the installation query
return query.find();
}).then(function(installations) {
var date = new Date();
// presumes underscore, but a regular for loop works too
_.each(installations, function(installation) {
installation.set("mostRecentPushDate", date);
});
return Parse.Object.saveAll(installations);
});
}
Then, wherever in your code you were building an installation query and calling push, call your new pushing function instead, like this:
var query = new Parse.Query(Parse.Installation);
query.equalTo('someColumn', someValue);
pushToInstallations(query, {alert: "some message"}).then(function(installations) {
// these installations passed back were pushed to and updated
}, function(error) {
// handle error
});
I have a Class in parse, say Pictures. Each of these belongs to a user. Reference to this user is stored in the Pictures table/class as a Pointer to the user.
In my cloud code I am trying to get all Pictures belonging to a user, using master key. Following is my code:
Parse.Cloud.define("getPictures", function(request, response) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("Pictures");
query.equalTo("user", request.params.user);
query.find({
success: function(results) {
var status = "Found " + results.length + " pictures for userId " + request.params.user;
response.success(status);
},
error: function() {
status = "No pictures exist for userId " + request.params.user;
response.error(status);
}
});
});
This code outputs that there are 0 pictures for a certain user with id 'xyz' for example. However, I can see that the user has a lot of pictures stored.
I have also verified that the problem is not with using master key, as I see in the console log that the code is being executed as master. Moreover, if I query for a picture by objectId, it does come out in the results, which means ACL is not the problem here.
I think I have to use relations/joining here, but I am not sure how to do that.
Pointers are stored as objects in Parse database, so if you try to compare a string to an object with query.equalTo() function, nothing will be found. This is how pointers are stored:
{
__type: 'Pointer',
className: '_User',
objectId: user-object-id
}
If you are querying a class with pointers and want your result comes with the whole object nested, you should set this in your query:
var query = new Parse.Query('Pictures');
query.include('user');
In my queries when I want to search by a pointer column, I compare my user object with the nested user object.
var user = new Parse.User();
// Set your id to desired user object id
user.id = your-user-id;
var query = new Parse.Query('Pictures');
// This include will make your query resut comes with the full object
// instead of just a pointer
query.include('user');
// Now you'll compare your local object to database objects
query.equalTo('user', user);
query.find({
success: function(userPicture) {
response.success(userPicture);
}
});
Anyway, seems that if you have many pictures related to an user, you probably are searching for parse relations instead of pointers: https://www.parse.com/docs/relations_guide
If you write a query to retrieve a parent object and a child object to which you have pointer, but no read access as per ACL, then the query may return only parent object and child will be null because the ACL wont let you read it.
There may be a problem with your params. If "user" is a pointer, then 'request.params.user' is incorrect, because PFObjects may not be sent as params. If "user" is a pointer, use 'request.user'. If request.params.user is a string of the userId, you could use the Id to reconstruct a PFObject shell before the query as was suggested by Murilo already, but deleting the "user" param and using request.user would shorten your code and not duplicate any values. Murilo's solution is also beneficial because you could pass a userId other than the current user's Id.