My database has the following structure:
"groupA" : {
"applications" : {
"applicationID_132" : {
"status" : "accepted"
},
"applicationID_423" : {
"status" : "declined"
},
"applicationID_562" : {
"status" : "accepted"
}
}
}
I am trying to retrieve the snapshot of applications with "accepted" status (to be able to skip fetching all applications) by:
return admin.database().ref('groupA').child('applications').orderByValue('status').equalTo('accepted')
.once('value')
.then(acceptedApplicationsSnapshot => {
Doesn't seem to work, tried orderBy and orderByValue as well. What might be missing or what is the better way to handle this case?
Thank you for any help!
Try using child.orderByChild().value()
In your case:
return admin.database().ref('groupA').child('applications').orderByChild('status').equalTo('accepted')
.once('value')
.then(acceptedApplicationsSnapshot => {
You could use orderByValue() as well, but first you would need to get the Reference which you want to order - function does not accept parameter.
How to use orderByValue()?
.child(..) returns a Reference in your case that is applications if you want to use orderByValue than you would need to get reference to 'status' before doing that, eg:
admin.database().ref('groupA').child('applications').child('status').orderByValue() and then you would apply one of the data filtering methods eg.
.equalTo('accepted')...
Related
Hello i am using mongoose.
I have built this query that finds my desired project :
const projects = await ClientManagers.findOne({'project.contactPerson.work_email' : 'testing#email.com'} , { 'project.$.companyName': 1 });
this returns an object from my database like this :
{
'projectName' : 'x',
'companyName' : 'x bv'
}
How can i update the company name to be 'Y bv' instead of 'x bv'.
Assuming this is your document structure,
{
"_id" : ObjectId("5f2ae5a4b1549ac0460920dd"),
"projectName" : "A",
"project" : [
{
"companyName" : "T1",
"contactPerson" : {
"work_email" : "t1#gmail.com"
}
},
{
"companyName" : "T2",
"contactPerson" : {
"work_email" : "t2#gmail.com"
}
}
]
}
Single Update updateOne()
If you know email will be unique and want to update single document then use updateOne().
first is query part to find condition, email t1#gmail.com
second is set/update part, here $ is for array because project is an array, update companyName to T1 Company
await ClientManagers.updateOne(
{ 'project.contactPerson.work_email': 't1#gmail.com' },
{
$set: { "project.$.companyName": "T1 Companmy" }
}
)
Multiple Update updateMany()
If email is not unique and want to update everywhere then use updateMany(), it will update every matching documents.
await ClientManagers.updateMany(
{ 'project.contactPerson.work_email': 't1#gmail.com' },
{
$set: { "project.$.companyName": "T1 Company" }
}
)
Not suggesting update() method to use, because its deprecated in mongoose and will give Deprecation Warnings
, this function is replaced with updateOne(), updateMany() and replaceOne() methods.
Good start. Mongo has better documentation with examples. I suggest you to refer that also.
use update
db.collection.update({companyName:'x bv'}, {"$set":{"companyName":y}})
Mongo is case sensitive. So name should match exactly.
update updates one document. To update multiple, use updateMany or multi:true option with update or findOneAndMondify for one update for find and update case.
I'am trying to build my query using sequelize, in the where clause I need to give the conditional value from my front-end so i did it like this :
getResults(req) {
return parm
.findAll({
attributes: [
sequelize.literal('DISTINCT "id"')
],
where : {
name: req.query.parm.replace(/"/g, '').split(',')
} ,
raw: true
});
}
and it's working!
but now I need to write a subquery including where clause:
something like this :
SELECT tab1.name FROM
(SELECT name FROM "MYTABLE"
WHERE id = (value from the front-end) AND name IN (values from front-end)
) as tab1
Here is what i have tried :
getTest(req) {
if (req.query.parm != null) {
return parm .sequelize.query('SELECT id FROM "table_base" where id = $mid ); ',
{ type: sequelize.QueryTypes.SELECT ,
bind: { mid: [req.query.parm.replace(/"/g, '').split(',')] }} );
}
},
i tried to use raw query and i tested the binding parameters but i get this error when i execute this testing query :
Executing (default): SELECT id FROM "table_base" where id = $1 );
The answer to your question is YES it is indeed possible! SQL can pretty much do anything even if you are using sequelize. If you write the subquery and it doesn't work just post it back here so people can take a look and debug. Thanks
Let's say I have these three documents:
{ "_id": "11111", "type": "template", "name": "person" }
{ "_id": "22222", "type": "template", "name": "place" }
{ "_id": "33333", "type": "template", "name": "thing" }
I have a cloud database and then I have a device with pouchDB syncing from that database.
These are the steps that I do:
I sync both databases together. So now I have the most recent versions of this document on my device.
I run the below query and I get back all three templates like so:
Code
var template_obj = {};
return device_db.query('filters/templates')
.then((templates) => {
for (let t of templates.rows) templates_obj[t.id] = true;
return templates_obj;
});
filters/templates
function (doc) {
if(doc.type == "template")
emit(doc._id);
}
return
{ "11111": true, "22222": true, "33333": true }
I update template: person on cloud. And then I update it again. So 2 revisions have gone by without syncing to my device.
I sync with my device.
Now when I run the same query and I only get back the document I edited. Which is weird because I haven't touched any of the other documents. The same view returns the expected results on the cloud but not on the device.
return
{"11111": true}
If I do the following code however, all templates come back as normal and the same _rev from the cloud show up on the device. Meaning the sync was successful and view is getting confused.
new code
return device_db.allDocs({conflicts: true})
.then((data) => {
for (let d of data.rows) {
if(d.doc.type == "template") {
templates_obj[d.doc._id] = true;
}
}
return templates_obj;
}).catch((err) => {
console.log(JSON.stringify(err));
})
I'm starting to believe this is a bug because if I destroy my database and do these steps again, I can reproduce this issue.
After realizing you are using React Native, I think this actually has to do with PouchDB in React Native, and it's indeed a bug. There are several reports of that behavior:
https://github.com/pouchdb/pouchdb/issues/7219
https://github.com/pouchdb/pouchdb/issues/7188
https://github.com/pouchdb/pouchdb/issues/7293
[edit: Seems to be a bug in PouchDB with React Native. I leave this answer because it might be helpful in other ways.]
I suspect it's some side effect with the global variable template_obj you are using. Try to console.log(templates.rows) directly instead of storing it in a variable in the top scope, or use Array.reduce() to avoid side effects. Then you'd always get the correct view results.
This is step by step code:
return device_db.query('filters/templates')
.then(templates => templates.rows) // Take only the rows into account.
.then(rows => rows.map(row => row.id) // Extract the id. If you wanted the name instead this would be possible with a slightly different view.
// I think it would suffice to log the result right now,
// but if you really want to have a single object with boolean values,
// you can do the following:
.then(ids => ids.reduce((asObject, id) => { // Use Array.reduce() here to avoid any potential side effects.
asObject[id] = true;
return asObject;
}, {})
.then(asObject => { console.log(asObject); }; // Debug the result.
Or more concise with ES2015+:
return device_db.query('filters/templates')
.then(({rows}) => rows.reduce((acc, {id}) => ({...acc, [id]: true }), {}))
.then(result => console.log(result))
By the way: You could also use other strategies to "filter" your documents, as it's not necessary to emit the _id. Instead you can use the key and/or value for "secondary indexes":
{
"_id": "_design/docs",
"views": {
"byType": "function(doc) { emit(doc.type); }",
"templatesByName": "function(doc) { if (doc.type === 'template') emit(doc.name); }",
"byTypeAndName": "function(doc) { emit([doc.type, doc.name], doc.name); }
}
}
you can use docs/byType as an universal view for other doc types too. Just call it with db.query('docs/byType', { key: 'template' })
If you want the templates sorted by name, use db.query('docs/templatesByName') or db.query('docs/byTypeAndName', { startkey: ['template'], endkey: ['template', {}]}).
A word of caution: This is all untested and just from memory, so some brackets might be missing in the code, or some bugs might hide in there.
It's not a bug in PDB, it's about outdated unfortunately components in pouchdb-react-native.
Confirmed way is to combine pouchdb-react-native yourself like this - then queries work as expected:
import PouchDB from 'pouchdb-core';
PouchDB
.plugin(require('pouchdb-adapter-asyncstorage').default)
.plugin(require('pouchdb-adapter-http'))
.plugin(require('pouchdb-mapreduce'))
.plugin(require('pouchdb-replication'))
.plugin(require('pouchdb-authentication'));
const localDB = new PouchDB(localDBname, {adapter: 'asyncstorage', auto_compaction: true});
This way one can be sure that all components are the latest.
I am trying to restrict writing to two related firebase nodes. I have a the following data structure on firebase:
"mainsibblings" : {
"-L9ygIWI-TKeNZvQ-TmP" : {
"MACaddress" : "111111111111",
},
},
"slavesibbling" : {
"111111111111" : {
"onMainSibling" : "-L9ygIWI-TKeNZvQ-TmP",
}
}
The slavesibbling pushkey is a unique MAC Address (freely created and updated by the user).
Conditions:
1) user should have permission to write a new mainsibbling and slavesibbling
2) shouldn't have permission to overwrite neither (mainsibbling & slavesibbling) if slavesibbling key (in this case: "111111111111") already exists.
3) the "owner" should be able to update both node even after he creates them
So if someone types a MAC Address that is registered already, the child nodes can't be updated, but if the user (referenced in ownerID) want to update a MAC Address he has created he should be able to do it.
How do I write the firebase database rules to control this?
I am trying this to prevent duplicates but it's not working:
"mainsibblings": {
".read": true,
"$pushKey": {
".write": "data.child('MACaddress').val() != newData.child('MACaddress').val()",
}
},
"slavesibbling": {
"$MACaddress":{
".read": true,
".write": "!data.hasChild(newData.val())",
}
}
This is the write operation I want to allow/disallow (I have replaced the MACaddress variable for a hardcoded MACaddress):
function AddSibblings(newMainSib, newSlaveSib) {
var MACaddress = "111111111111";
var ownerID = "QXXds7d33ceyecc4inoe33p_3";
mainRef.child(MACaddress).set(this.newMainSib);
otherRef.child(MACaddress).set(this.newSlaveSib)
mainRef.child(MACaddress).child('ownerID').set(ownerID);
otherRef.child(MACaddress).child('ownerID').set(ownerID);
otherRef.child(MACaddress).child('onMainSibbling').set(MACaddress);
}
There is no way in Firebase security rules to find whether a specific value exists in a list of children. If you want to ensure that a value is unique, you should use that value as the key of a collection.
For example in your case you can easily change the data to use the MAC address as the key for both mainsiblings and slavesiblings:
"mainsiblings" : {
"111111111111" : {
"MACaddress" : "111111111111",
},
},
"slavesibbling" : {
"111111111111" : {
"onMainSibling" : "111111111111",
}
}
And
"mainsiblings" : {
"111111111111" : {
"MACaddress" : "111111111111",
},
"223344556677" : {
"MACaddress" : "223344556677",
}
},
"slavesibbling" : {
"111111111111" : {
"onMainSibling" : "111111111111",
},
"223344556677" : {
"onMainSibling" : "223344556677",
}
}
Since property names are by definition unique in JSON, there is no way to have duplicate MAC addresses in this data structure.
Also see:
Firebase android : make username unique
How do you prevent duplicate user properties in Firebase?
Firebase security rules to check unique value of a child #AskFirebase
unique property in Firebase
Enforcing unique usernames with Firebase simplelogin
My data structure looks like this (removed unnecessary parts):
{
"threads" : {
"PUSHID" : {
"info" : {
"members" : {
"uid" : true,
"uid2" : true
}
}
}
}
}
I'm trying to write some javascript to pull snapshots of threads a user is in, but I can't figure out a way for it to work without pulling snapshots of each thread. This is my code now that pulls each thread snapshot.
firebase.database().ref('threads').on('child_added', function(snapshot) {
if (snapshot.hasChild('info/members/' + userUid)) {
// Display thread info
}
});
I tried to make a query with .orderByChild('info/members/' + userUid) and removing null snapshots, but I would have to add a .indexOn for each userUid which is obviously not practical.
Your current structure makes it easy/efficient to look up the users for a thread. But your use case is to look up the threads for a user. You'll need to augment your data model to allow the use-case:
{
"user_threads" : {
"uid": {
"PUSHID": true,
"PUSHID2": true
},
"uid2": {
"PUSHID": true,
"PUSHID3": true
}
}
}
And then read it with:
firebase.database().ref('user_threads/'+userUid).on('child_added', function(snapshot) {
...
});
Modifying/expanding your data model to match the use-cases of your app is quite common when using NoSQL databases.