Query Firebase Database Swift - json

I've been trying to create some queries for my database but without success. This is the first time when dealing with queries in Firebase and find them a bit confusing.
I use a real-time database
My database looks like this :
-> users
->profile
->uid1
->email : "some#email.com"
->name : "some_name"
->favourite
->id1
->title : "some_title"
->date : "some_date"
->id : "id1"
->id2
->title : "some_title"
->date : "some_date"
->id : "id2"
->uid2
->email : "some#email.com"
->name : "some_name"
->favourite
->id1
->title : "some_title"
->date : "some_date"
->id : "id1"
->id2
->title : "some_title"
->date : "some_date"
->id : "id2"
The queries I've been trying to make:
Check whether a specific uid is already in the database.
Check whether a specific id from favourite is already in the database at a known uid.
Any ideas how to perform these queries?

Depends if you are using the real-time database or Firestore. But because you want to do queries I suggest to use Firestore and you could implement it this way:
// Create a path where you want the query to search
let storageReference = Firestore.firestore().collection("users/profile")
let query = storageReference.whereField("uid", isEqualTo: givenUID )
query.getDocuments { (snapshot, error) in
if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
}
}
}
In real-time database you can't use queries but you can implement it like this and see if the document is available:
let databaseRef = Database.database().reference(withPath: "users/profile/givenUID")
databaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
// UID is in the database
} else {
// UID not found
}
})
Then do the same with a reference for favorites!

Related

If then else in json

Set values based on the ip address in JSON with if the else
Using perl JSON module.
I'm trying to setup my etc/config.json so that I never have to edit it when I move code from development->staging->production.
sql ip addresses will be different for different VM's
{
"html_title" : "Bogus",
"local_ip" :
"default" : "[production]",
"hosts" :
{
"production" :
{
"10.11.12.13" : "b102-vm",
"10.11.12.14" : "b103-vm"
},
"stage" :
{
"10.11.12.15" : "b102-vm-s",
"10.11.12.16" : "b103-vm-s"
},
},
"production" :
{
"some_schema" :
{
"host" : "10.11.12.13",
"database" : "some_table",
"dsn" : "DBI:mysql:[production.some_schema.database]:[production.some_schema.host]",
"user" : "user",
"pass" : "pass"
}
},
"stage" :
{
"some_schema" :
{
"host" : "10.11.12.16",
"database" : "some_table",
"dsn" : "DBI:mysql:[stage.some_schema.database]:[stage.some_schema.host]",
"user" : "user",
"pass" : "pass"
}
},
"if" : HERE IS WHERE I GET LOST.
{
"local_ip" : {
"anyOf" : ["[hosts.production]"]
}
},
"then" : { "default" : "[production]" }
"else" :
{
"if" :
{
"local_ip" : {
"anyOf" : ["[hosts.stage]"]
}
},
"then" : { "default" : "[production]" }
}
}
Would like to see "default" point to the production or stage values
As others have pointed out in the comments, JSON is not a programming language; it is a data storage format.
I can think of two obvious ways to do this. Yours is, I'm sorry to say, not one of them.
Both of my solutions involve your various systems having an environment variable set which identifies the kind of environment it is. I'm also going to assume some kind of get_config() function that reads a config file and returns a Perl data structure of the config.
Solution 1: Separate files
Have two files called "staging.json" and "production.json". The get_config() function reads the required one.
sub get_config {
my %valid_env = (
staging => 1,
production => 1,
);
die "$ENV{ENVIRONMENT} is not a valid environment type\n"
unless $valid_env{$ENV{ENVIRONMENT}};
my $json = read_file("$ENV{ENVIRONMENT}.json");
return JSON->new->decode($json);
}
As an extension to this, you could have three files - common.json, staging.json and production.json. You'd always read common.json along with the correct environment file and merge the two data structures into one before returning the data.
Solution 2: Munge the config
Stick with your existing file but munge the data structure after you've read it and before you return it.
sub get_config {
my %valid_env = (
staging => 1,
production => 1,
);
die "$ENV{ENVIRONMENT} is not a valid environment type\n"
unless $valid_env{$ENV{ENVIRONMENT}};
my $json = read_file('config.json');
my $config = JSON->new->decode($json);
# Use $ENV{ENVIRONMENT} to munge the contents of $config
# so it only contains data about the current environment
return $config;
}

Sequelize - Where clause in a nested 'include' statement does return results correctly in Node

I have 5 db tables:
Template, Capability, Deployment, Level, Requirement
Template (PK) -> has many Capability (FK)
Capability (PK) -> has many Deployments (FK) && Capability has many Levels (FK)
Level (PK) -> has many Requirement (FK)
I want to retrieve all templates, with the related foreign keys all the way down to the Requirements.
However, I would like to limit the number of Levels to just the ones that are not deleted (isDeleted : false).
This works if there is DATA retrieved, BUT if there are no records returned from the Levels tables based on the Where (isDeleted), Sequelize will return an empty array for the Deployments table as well. This query correct data if records are found from the Levels table. However, shouldn't the records from the deployment table be returned regardless since it is a different table?
Template.hasMany(Capability, { foreignKey : {name : 'templateId'} })
Capability.hasMany(Deployment, { foreignKey : {name : 'capabilityId'} });
Capability.hasMany(Level, {foreignKey : {name : 'capabilityId'} });
Level.hasMany(Requirement, {foreignKey : {name : 'levelId'}});
const allModules =
await Template.findAll({
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments'
},{
model: Level,
as : 'levels',
where : { isDeleted : false }, // this is the failing part ( if no records are returned both the Deployment recordset and the Level recordset fail)
include : [{
model : Requirement,
as : 'requirements',
}],
},]
}],
})
You might be asking for something impossible. You said:
Capability.hasMany(Level, ...
Level.hasMany(Requirement ....
If there is no Level (or, if the level is marked as deleted), the link between Capability and Requirement is broken, so those Requirements cannot be retrieved. Under what capability would they appear?
OTOH, If you're looking for other outer join situations, try required : false. For example, you could add this to your query to retrieve Capabilities that have no deployments as follows:
...
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments',
required : false // outer join
}
...

Fires query to return a single child and update a value

I have a function that queries Firebase using .queryEqual to get me th node I want to update but I do not know how to set the value to false. Here is the function I have:
func addrShipDefault() {
let ref = Router.addrShip.reference().child(self.userId)
let query = ref.queryOrdered(byChild: "isDefault").queryEqual(toValue: true)
query.setValue(false, "isDefault")
}
Would someone be able to tell me how to query Firebase for the node I am looking for and update its value?
I have done other updates using ref.updateChildValues, but for those I know the exact path. This time I need to lookup the node that has isDefault set to true and modify it.
Hope this makes sense!!
Thank you for the help
**** UPDATE TO SHOW DB STRUCTURE
{
"addr_01" : {
"address1" : "63 Park Ave",
"address2" : "Unit #2",
"city" : "Greenland",
"firstName" : "John",
"id" : "addr_01",
"isDefault" : true,
"lastName" : "Smith",
"state" : "MA",
"zipcode" : "01890"
},
"addr_02" : {
"address1" : "101 Lafayette Rd",
"address2" : "",
"city" : "Rye",
"firstName" : "Say It In 3D",
"id" : "addr_02",
"isDefault" : false,
"lastName" : "",
"state" : "NH",
"zipcode" : "03870"
}
}
From the official documentation here
you can update a child
without rewriting the entire object. If you want to allow users to
update their profiles you could update the username as follows:
self.ref.child("users/(user.uid)/username").setValue(username)
Now using the above example in your case:
We can do something like this: (I havent tried it but I think you can get the idea)
let ref = Router.addrShip.reference().child(self.userId)
let query = ref.queryOrdered(byChild: "isDefault").queryEqual(toValue: true)
//query.child("isDefault").setValue(false)
//Updated Code
query.observeSingleEvent(of: .childAdded) { (snapshot) in
let newRef = snapshot.ref.child("isDefault")
newRef.setValue(false, withCompletionBlock: { (err, ref) in
print("SetValue")
})
}
Note that from official documentation here
Function signature for setValue method is as follows:
func setValue(_ value: Any?)
As can be seen above, it accepts optional of any type value, which means you can pass any value for valid json.
Also note that there is also a method with completion block
func setValue(_ value: Any?, withCompletionBlock block: #escaping (Error?, DatabaseReference) -> Void)

Writing mongoDb queries using mongoose to create node api

I have some mongoDb collections 'classrooms' and 'students' of the form:
Classrooms:
{
"_id" : ObjectId("56c7219dbd5f92cd78ae4b7e"),
"name" : "My Students",
"user" : ObjectId("56c7218cbd5f92cd78ae4b7c"),
"updatedAt" : ISODate("2016-02-19T14:07:25.965+0000"),
"createdAt" : ISODate("2016-02-19T14:07:25.965+0000"),
"students" : [
ObjectId("56dbb26cff34aa686c0d9d25"),
ObjectId("56f7c2bf1982aa9219ae8843")
],
"role" : "user",
"allowDelete" : false,
"__v" : NumberInt(0)
}
Students:
{
"_id" : ObjectId("56dbb26cff34aa686c0d9d25"),
"email" : "1989manjari#gmail.com",
"createdBy" : ObjectId("56c7218cbd5f92cd78ae4b7c"),
"classRoom" : ObjectId("56c7219dbd5f92cd78ae4b7e"),
"mentorEmail" : "gauravatbits#gmail.com",
"studentId" : ObjectId("56ced54303b7cb7b0eda9862"),
"status" : true,
"updatedAt" : ISODate("2016-03-11T15:32:36.806+0000"),
"autoAdd" : true,
"createdAt" : ISODate("2016-03-06T04:30:36.073+0000"),
"__v" : NumberInt(0)
}
My query is:
id_list = db.classrooms.distinct("students");
db.students.find({_id: {$in: id_list}, studentId:{$exists:false}},{email:1, mentorEmail: 1}).pretty()
Now I want to create an endpoint in node api for this response. So i wanted to know how can I write these queries in Mongoose and create endpoint like: app.get('/api/myquery') to get the json result.
P.S. : Is it possible to do this, without creating schema in Mongoose because i also have some collections which have large no. of fields(38 fields). I just want to get some json data by applying queries in already existing collections.
something like this with mongoose
just pseudo code
var model = mongoose.model("collection", mongooseSchema)
app.get('/api/myquery', function(){
model.find({_id : id_list}, "email mentorEmail", function(err, data){
if(err)throw err;
res.json(data) // maybe use JSON.stringify() if didnt get json but that sets application/json in header of HTTP
})
})
You can directly insert jsons in mongoose but you should keep in mind that only that data will be read which are mentioned in the models in mongoose. Do keeping 38 fields is not a problem just insert in directly.

Imported MySQL database to MongoDB - One to Many relationship id's update

I imported my MySQL database to MongoDB using MongoVUE.
First let me make an example of my tables:
Table0 = 1,500 entries
Table1 = 120,000 entries
Table2 = 18,000,000 entries
Table0 -> hasMany -> Table1 entries
Table1 -> hasMany -> Table2 entries
All tables have a _id key now but after the import both tables still have an id key from MySQL.
How do I updated table2's keys table1_id to match table1's _id key? Is it doable using a Mongo query or should I have to write a script for that? (The only language I know is PHP and Javascript/NodeJS)
Update 1
Using user #profesor79 answer I made this query where table1 = market_item_histories and table2 = market_items
db.market_item_histories.aggregate([
{
$lookup: {
from:"market_items",
localField: "market_item_id",
foreignField: "id",
as: "market_items_docs"
}
},
{
$unwind:"$market_items_docs"
},
{
$project: {
_id:1,
oldId:"$market_item_id",
market_item_id:"$market_items_docs._id",
date:1,
price:1,
amount:1,
created_at:1,
updated_at:1
}
},
{
$out:"marketItemHistories"
}
])
When running that code I get this Error:
assert: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
Error: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:254:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1278:12)
at (shell):1:26
2016-04-29T14:13:48.223+0000 E QUERY Error: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:254:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1278:12)
at (shell):1:26 at src/mongo/shell/assert.js:13
this is a nice real life problem.
To get this done we can use aggregation framework and "join" tables, then write results in new collection.
After that the source can be renamed/deleted and our out can be renamed too.
This was done using mongo console.
Please find solution for joining table1 with table0, and use this to perform on others joins.
db.table1.aggregate([
{
$lookup:{
from:"table0",
localField: "table0_Id", // this is our join source
foreignField: "id", // this id field in table0 collection
as: "table0_docs"
}
},
{
$unwind:"$table0_docs"
},
{
$project:{
// very important list all fields here
_id:1,
data:1,
oldId:"$table0_Id",
referenceID:"$table0_docs._id",
}
},
{
$out:"newCollectionName"
}
])
AND OUTPUT DOCUMENT
{
"_id" : ObjectId("57234f5de63d33670e521892"),
"data" : "22",
"oldId" : 1,
"referenceID" : ObjectId("57234f33e63d33670e52188e")
}
Any comments welcome!