Firebase multi-path update set a parent node to null - node.js

I am trying to use firebase realtime database multi path updates.
However trying to set a parent node to null as below will result on an error.
const firebaseUpdate = {}
firebaseUpdate[`user/${uid}`] = null
db.ref().update(firebaseUpdate)
Error: Reference.update failed: First argument contains a path /user/USER_ID
that is ancestor of another path /user/USER_ID/creationTime
I was wondering if there is a way to use multi-path updates in order to set a parent node with multiple children to null.
I assume I could use remove or set function but I'd rather use the multi-path update.

The error message indicates that you're trying to apply two conflicting updates to the database in one operation. As the message says, your update tries to:
write to /user/USER_ID
write to /user/USER_ID/creationTime
The second one write is a child of the first one. Since the order of writes in a multi-location is unspecified, it's impossible to say what the outcome of the write operation will be.
If you want to replace any data that currently exists at /user/USER_ID with the creationTime, you should update it like this:
db.ref().update({
"/user/USER_ID": { creationTime: Date.now() }
})

Related

Firebase how to read latest children node?

I'm new to firebase and currently I'm still trying to learn how to get the latest children node based in this RTDB. My nodeMCU will send new data periodically so I'm trying to get the latest node when its added and the value of that node. Can you provide with a sample code for me to understand better? And if possible please explain like I'm 5. Thank you and have a good day.
From what I understand you have an Arduino module that is going to be constantly introducing data into your database.
What you want is to be able to read the value shown in the image as MQ7 every time a new value is added.
If this is the case there are different ways to obtain it.
The first and most common one would be to use the firebase Child Added event. With this event you can handle the data entered every time there is an addition to the reference to the database.
Using this event you would have a set of all the values entered in your reference and with each addition automatically (In Real Time) this set would be updated.
Taking your image as an example, the query code would be something like this (JS):
dbRef.child("Sensor MQ7").on("child_added", (snap) => {
for (i in snap.val()) {
const value_MQ7 = snap.child(i).child("MQ7").val()
// Do what you want with the value
console.log(value_MQ7)
}
})
If you don’t want to have that set with all the values entered in your reference, the best option would be a new function that returns only the value you are requesting, that is, a function that returns the MQ7 value of the last object entered in your reference sensor MQ7.
The query code would be something like this (JS):
const query = dbRef.child("Sensor MQ7").orderByKey().limitToLast(1);
query.get().then((snap) => {
for (i in snap.val()) {
// Do what you want with the value
const value_MQ7 = snap.child(i).child("MQ7").val()
console.log(value_MQ7)
}
})

Returning the altered (by apoc.trigger) version of node instead of the original

I am using the python bolt driver to create nodes in a neo4j database. These nodes get altered by apoc.trigger functions. And i want the returning BoltStatementResult to contain the altered version of these nodes.
This is what i have tested so far:
My triggers are working as expected. The nodes stored, are altered correctly.
I tried the 'before' and 'after' phases.
I set the trigger functions to return the altered version.
I did write a second query to get the new and updated node of database. But this option is quite unsafe, as it has no unique identifier.
My trigger function:
CALL apoc.trigger.add(
'onCreateNodeAddMetadata',
'UNWIND {createdNodes} AS n
SET n.uid = apoc.create.uuid(), n.timestamp = timestamp() RETURN n',
{phase: 'before'}
)
I expect the returning value of my session.write_transaction to contain the the added properties.
As a safe workaround (but see caveat below), the Cypher query in your write_transaction can return the native ID of the created node (e.g., RETURN ID(n)).
Then, as long as you know the node was not deleted, you can perform a query for it with that ID (in this example, myID contains the ID value and is passed as a parameter):
MATCH (n) WHERE ID(n) = $myId
...
If the node could be deleted before you search for it by native ID, then this technique is not safe, since neo4j can re-assign the native ID of a deleted node to another newly- created node.

Drupal 6 - is node_submit() needed when saving node?

I'm trying to fix problem in some legacy code which is generating nodes of custom content type "show", but only if node in same type and with same title doesn't exist already. Code looks like:
$program = node_load(array('title' => $xml_node->program_title, 'type' => 'show'));
if (!$program) {
$program = new stdClass();
$program->type = 'show';
...
node_submit($program);
node_save($program);
}
So, script is first trying to load node in 'show' content type with specific title and if it fails it creates one.
Problem is, when it's called multiple times in short period of time (inside a loop) it creates double nodes. Like 2 shows with the same title created in same second?!?
What can be the problem there?
I was looking examples for how to save node in Drupal 6. In some they don't even call node_submit() . Is that call needed? If so, do I maybe have to pass to node_save() what node_submit() returned? Or maybe node_load() fails to load existing node for some reason? Maybe some cache has to be cleared or something?
As far as i know and used node_save to create nodes programmaticly there is no need for the node_submit() function.
The reason that double nodes are created is that the node_load() function fired before completing the updates to the node_load() cache. Try to add:
node_load(FALSE, NULL, TRUE);
after node_save($program).
this will clear the node_load() cache.
see:
https://api.drupal.org/comment/12084#comment-12084

BizTalk: Getting error in Promoted Property

I am getting below error when I run the Orchestration and try to assign value to a promoted property by reading the value of another promoted property.
Error in Suspended Orchestration:
Inner exception: There is no value associated with the property BankProcesses.Schemas.Internal_ID' in the message.
Detail:
I have 2 XSD schemas, 1 for calling a stored procedure and reading its response and another to write it into a flat file. The internal ID returned in the response from SP needs to be passed to a node in another XSD schema to write to a flat file format.
I have promoted an element from the response schema and also promoted an element from the schema to write to flat file. I am assigning the value to promoted propeties as below:
strInternalId = msgCallHeaderSP_Response(BankProcesses.Schemas.Internal_ID);
msgCallSP(BankProcesses.Schemas.Header_Internal_ID) = strInternalId;
But when I run the orchestration I get the error as mentioned above. I have checked the reponse from stored procedure and the reponse XML does contain some value but I am unable to assign that value to another schema. Please advice
Thanks,
Mayur
You can use exists to check the existence of property.
if(BankProcesses.Schemas.Internal_ID exists msgCallHeaderSP_Response)
{
strInternalId = msgCallHeaderSP_Response(BankProcesses.Schemas.Internal_ID);
msgCallSP(BankProcesses.Schemas.Header_Internal_ID) = strInternalId;
}
One scenario that might cause this error is that there is no Header_Internal_ID element in the message you are trying to modify. Can you inspect the message before modification to ensure that there is an element whose value should be changed - drop the message out to a file location, maybe.
If this is the case, then just ensure that you create this element when you instantiate you r message for the first time - even if you initially set it to an empty element.
HTH
To check if the property exists, you can use this syntax:
BMWFS.LS.BizTalk.CFS.BankProcesses.Schemas.Internal_ID exists msgCallHeaderSP_Response
However, if the case is that the source field would always be there, you have to work backwards to find out why the Property is not appearing on the Context.
If it's coming from a Port, is the message passign through an XmlDisassembler Component? If it's coming from another Orchestration, are you actually setting the Property?
The easiest way to look at the Context is to route the Message, msgCallHeaderSP_Response, to a Stopped Send Port. You can then view the Context in BizTalk Administrator.

node-postgres: how to prepare a statement without executing the query?

I want to create a "prepared statement" in postgres using the node-postgres module. I want to create it without binding it to parameters because the binding will take place in a loop.
In the documentation i read :
query(object config, optional function callback) : Query
If _text_ and _name_ are provided within the config, the query will result in the creation of a prepared statement.
I tried
client.query({"name":"mystatement", "text":"select id from mytable where id=$1"});
but when I try passing only the text & name keys in the config object, I get an exception :
(translated) message is binding 0 parameters but the prepared statement expects 1
Is there something I am missing ? How do you create/prepare a statement without binding it to specific value in order to avoid re-preparing the statement in every step of a loop ?
I just found an answer on this issue by the author of node-postgres.
With node-postgres the first time you issue a named query it is
parsed, bound, and executed all at once. Every subsequent query issued
on the same connection with the same name will automatically skip the
"parse" step and only rebind and execute the already planned query.
Currently node-postgres does not support a way to create a named,
prepared query and not execute the query. This feature is supported
within libpq and the client/server protocol (used by the pure
javascript bindings), but I've not directly exposed it in the API. I
thought it would add complexity to the API without any real benefit.
Since named statements are bound to the client in which they are
created, if the client is disconnected and reconnected or a different
client is returned from the client pool, the named statement will no
longer work (it requires a re-parsing).
You can use pg-prepared for that:
var prep = require('pg-prepared')
// First prepare statement without binding parameters
var item = prep('select id from mytable where id=${id}')
// Then execute the query and bind parameters in loop
for (i in [1,2,3]) {
client.query(item({id: i}), function(err, result) {...})
}
Update: Reading your question again, here's what I believe you need to do. You need to pass a "value" array as well.
Just to clarify; where you would normally "prepare" your query, just prepare the object you pass to it, without the value array. Then where you would normally "execute" your query, set the value array in the object and pass it to the query. If it's the first time, the driver will do the actual prepare for you the first time around, and simple do binding and execution for the rest of the iteration.

Resources