Query object in child array - ios

I am trying to use a query to retrieve data of student who are only 4 years old from my database but i cant figure out how to use Firebase to query the age (The array in each child).
{
"student" : {
"-Kv2RVDDsI-v6V7g_LBn" : [ {
"name" : "sam",
"age" : "6"
}, {
"name" : "tom",
"age" : "4"
}
],
"-hguyu-v6V7g_LBn" : [ {
"name" : "Tim",
"age" : "12"
}, {
"name" : "tom",
"age" : "4"
}
]
}
}
This is my code but it does no return anything.
ref.child("student").queryOrdered(byChild: "age").queryEqual(toValue: 4).observe(.childAdded, with: { (snapshot) in
let value = snapshot.value
print(value)
}) { (error) in
print(error.localizedDescription)
}
However, if i remove the queryOrdered(byChild: "age") it works.
Thanks.

You are referencing "Student" when actually your JSON database format child path name is "Students".
Also make sure that you are querying by key. Refer to the Firebase documentation to see how to query by key. I don't understand your structure though why you have 2 children per key.
Why not have a new key for each child?

Related

How to retrieve the User info?

I want to retrieve data uid in User table data but for a specific user , I have 2 users, and it seems that it grabs the 2 users uid but I want to grab with i speficy not both of them just one.
Thank You In advance
let specificDatabase = Database.database().reference()
specificDatabase.queryOrdered(byChild: "User/FirstName").queryEqual(toValue: "The user first name")
specificDatabase.observeSingleEvent(of: .value) { (snapShot: DataSnapshot) in
for child in snapShot.children {
print(snapShot.key)
}
}
Firebase Data Structure
"User" : {
"ez8sTAsqXTWfnuzizUXU69VS4qM2" : {
"FirstName" : "other",
"LastName" : "Martin",
"uid" : "ez8sTAsqXTWfnuzizUXU69VS4qM2"
},
}
"Data" : {
"ez8sTAsqXTWfnuzizUXU69VS4qM2" : {
"-Ll7jUYg6BxRAhWPLskg" : {
"Name" : "other Martin",
"Data1" : "data"
},
"-Ll7jW_elQIPTLESwDYD" : {
"Name" : "other Martin",
"Data1" : "data "
}
},
}
You're telling Firebase to order each child node of the root by its User/FirstName property and then filter on that. Since the child nodes of the root don't have a property at that path, the query returns no results.
Instead you want to order/filter each child node of /User by itsFirstName property, which you can do with:
let specificDatabase = Database.database().reference(withPath: "User")
specificDatabase.queryOrdered(byChild: "FirstName").queryEqual(toValue: "other")

Getting nested children from Firebase Database

I am attempting to populate a table view with values from my Firebase database. I was able to use queryOrdered on the root of my database to get the children I required, as seen here:
func oneTimeInit() {
databaseRef?.queryOrdered(byChild: "Seasons").observe(.value, with:
{ snapshot in
for item in snapshot.children {
self.seasons.append(Season( snapshot: item as! DataSnapshot))
}
self.seasonsTableView.reloadData()
})
}
But now I am trying to get the children of the next node in my database. I tried to do this by calling queryOrdered on the child of the root but I'm not getting any data. Here is my code:
func oneTimeInit() {
databaseRef?.child("Seasons").queryOrdered(byChild: season.name).observe(.value, with:
{ snapshot in
for item in snapshot.children {
print("ITEM VALUE: \(item)")
self.races.append(Race(snapshot: item as! DataSnapshot))
}
self.racesTableView.reloadData()
})
}
The Database contains, at its highest level, Cross Country Seasons, which each contain Cross Country Races, which each contain results. Im able to populate the Seasons table but not the Races table, and so on.
Heres the Json structure of my database:
{
"Seasons" : {
"XC 2018" : {
"NCAA DI West Regional" : {
"Men" : {
"Results" : {
"Aaron BRUMBAUGH" : {
"finishTime" : "31:59.0",
"lapTimes" : [ "5:05.1", "10:43.3", "11:07.1", "5:03.5" ],
"name" : "Aaron BRUMBAUGH",
"position" : "118",
"splitTimes" : [ "5:05.1", "15:48.4", "26:55.5", "31:59.0" ],
"team" : "Santa Clara",
"year" : "SR"
},
"Addison DEHAVEN" : {
"finishTime" : "29:47.8",
"lapTimes" : [ "4:58.2", "10:14.0", "10:04.1", "4:31.5" ],
"name" : "Addison DEHAVEN",
"position" : "7",
"splitTimes" : [ "4:58.2", "15:12.2", "25:16.3", "29:47.8" ],
"team" : "Boise State",
"year" : "SR"
},
"Ahmed MUHUMED" : {
"finishTime" : "30:08.1",
"lapTimes" : [ "4:58.6", "10:14.6", "10:08.5", "4:46.4" ],
"name" : "Ahmed MUHUMED",
"position" : "29",
"splitTimes" : [ "4:58.6", "15:13.2", "25:21.7", "30:08.1" ],
"team" : "Boise State",
"year" : "SO"
},
As of now there is only one "Season" (XC 2018) with one "Race" (NCAA D1 West Regional). I'm trying to get a reference to all of the "Races" under the "Season" XC 2018.
The variable season.name would contain the value "XC 2018". With my second one time init I am trying to look at the children of "XC 2018".

Firebase fanout data to update specific fields remove other siblings fields

Each user has a conversation node, each time a new conversation has a new message I need to update both conversation nodes for the two user involved in the conversation, I want just to update the "lastMessage" and "tinestamp" fields here is my try:
let fanoutObject = [userPath : dataToUpdate,
otherUserPath : dataToUpdate]
K.FirebaseRef.root.updateChildValues(fanoutObject)
where the paths for each user is:
"/users/{userID}/conversations/{conversationID}"
and the dataToUpdate:
let dataToUpdate:[String:AnyObject] = ["timestamp" : message.timestamp,
"lastMessage": message.textBody]
Result:
The node conversations for each user is updated BUT other fields in the conversation node are removed !
the conversation node fro each user is:
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"seen" : true,
"timestamp" : 1467849600000,
"with" : {
"country" : "US",
"firstName" : "John",
"profileImage" : "https://..."
}
}
}
note that the node conversations is inside a node user which is an element inside the root node users
and after update it's :
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"timestamp" : 1467849600000,
}
}
but I was expecting just to update the two values and keep others ?
According to docs my code should works:
updateChildValues Update some of the keys for a defined path without
replacing all of the data.
It's a bit hard to parse your code, but most likely it's the behavior of updateChildValues() that is confusing you.
When you call updateChildValues(), the Firebase server will loop over the object that you pass in. For each path in there, it will replace the entire value at that path with the value from that you passed in.
So if your current JSON is:
{
"Users": {
"uidForUser1": {
"name": "iOSGeek",
"id": 2305342
},
"uidForUser2": {
"name": "Frank van Puffelen",
"id": 209103
}
}
And the update is (in JSON format, the lingua franca of the Firebase Database):
{
"users/uidForUser2/name": "puf",
"users/uidForUser1/name": "My actual name"
}
Your resultant JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name",
"id": 2305342
},
"uidForUser2": {
"name": "puf",
"id": 209103
}
}
But if you send the following update:
{
"users/uidForUser1": {
"name": "My actual name"
},
"users/uidForUser2": {
"name": "puf"
}
}
The resulting JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name"
},
"uidForUser2": {
"name": "puf"
}
}
Update
To update two fields in the same object, but leave the other fields unmodified:
{
"path/to/object/field1": "new value",
"path/to/object/field2": "new value2"
}
Alternatively, you can update the lastMessage and timeStamp data by replacing the old values by providing full path :
let lastMessagePath = "/users/{userID}/conversations/{conversationID}/lastMessage"
let lastTimeStampPath = "/users/{userID}/conversations/{conversationID}/timestamp"
K.FirebaseRef.child(lastMessagePath).setValue(message.timestamp)
K.FirebaseRef.child(lastTimeStampPath).setValue(message.textBody)

Firebase ios: get list of users by IDs

Situation: I have a database with users, users can have friends and friends are linked to current user model as userID. So when I'm loading user data I'm receiving also a list of firebase IDs of his friends.
Question: Is there any way to receive firebase snapshot with all this users at once? Haven't found any suitable solution - .child() is linking directly with one object, queryOrderedByChild() and queryOrderedByValue() doesn't seem to make such requests.
Will be grateful for any advice.
Edit: Database structure:
{
"Users": {
"user_id_first" : {
"user_info" : {
"name": "name",
"age": "age"
},
"friends": {}
},
"user_id_second" : {
"user_info" : {
"name": "name",
"age": "age"
},
"friends": {}
},
"user_id_third" : {
"user_info" : {
"name": "name",
"age": "age"
},
"friends": {
"user_id_first" : true,
"user_id_second" : true
}
}
}
}
There are list of friend IDs, which are actually IDs of firebase users. All I need is to retrieve information for these users in one firebase snapshot (i.e. use one reference) without creating new reference for each friend like
myDBRef.child("Users").child("friend_id")
Use for loop to access all the friendsId :-
let parentRef = FIRDatabase.database().reference().child("Users")
parentRef.child(FIRAuth.auth()!.currentUser!.uid).child("friends").observeEventType(.Value, withBlock: {(snapshot) in
if snapshot.exists(){
if let friendsDictionary = snapshot.Value as! NSMutableDictionary{
for each in friendsDictionary as! [String : AnyObject]{
let friendsId = each.0 as! String
parentRef.child(friendId).observeEventType(.Value, withBlock: {(friendDictionary)
if let friendsInfo = friendDictionary.Value as! NSMutableDictionary{
//retrieve the info
}
})
}
}
}
})

How to join query in mongodb?

I have user document collection like this:
User {
id:"001"
name:"John",
age:30,
friends:["userId1","userId2","userId3"....]
}
A user has many friends, I have the following query in SQL:
select * from user where in (select friends from user where id=?) order by age
I would like to have something similar in MongoDB.
To have everything with just one query using the $lookup feature of the aggregation framework, try this :
db.User.aggregate(
[
// First step is to extract the "friends" field to work with the values
{
$unwind: "$friends"
},
// Lookup all the linked friends from the User collection
{
$lookup:
{
from: "User",
localField: "friends",
foreignField: "_id",
as: "friendsData"
}
},
// Sort the results by age
{
$sort: { 'friendsData.age': 1 }
},
// Get the results into a single array
{
$unwind: "$friendsData"
},
// Group the friends by user id
{
$group:
{
_id: "$_id",
friends: { $push: "$friends" },
friendsData: { $push: "$friendsData" }
}
}
]
)
Let's say the content of your User collection is the following:
{
"_id" : ObjectId("573b09e6322304d5e7c6256e"),
"name" : "John",
"age" : 30,
"friends" : [
"userId1",
"userId2",
"userId3"
]
}
{ "_id" : "userId1", "name" : "Derek", "age" : 34 }
{ "_id" : "userId2", "name" : "Homer", "age" : 44 }
{ "_id" : "userId3", "name" : "Bobby", "age" : 12 }
The result of the query will be:
{
"_id" : ObjectId("573b09e6322304d5e7c6256e"),
"friends" : [
"userId3",
"userId1",
"userId2"
],
"friendsData" : [
{
"_id" : "userId3",
"name" : "Bobby",
"age" : 12
},
{
"_id" : "userId1",
"name" : "Derek",
"age" : 34
},
{
"_id" : "userId2",
"name" : "Homer",
"age" : 44
}
]
}
Edit: this answer only applies to versions of MongoDb prior to v3.2.
You can't do what you want in just one query. You would have to first retrieve the list of friend user ids, then pass those ids to the second query to retrieve the documents and sort them by age.
var user = db.user.findOne({"id" : "001"}, {"friends": 1})
db.user.find( {"id" : {$in : user.friends }}).sort("age" : 1);
https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/
This is the doc for join query in mongodb , this is new feature from version 3.2.
So this will be helpful.
You can use in Moongoose JS .populate() and { populate : { path : 'field' } }.
Example:
Models:
mongoose.model('users', new Schema({
name:String,
status: true,
friends: [{type: Schema.Types.ObjectId, ref:'users'}],
posts: [{type: Schema.Types.ObjectId, ref:'posts'}],
}));
mongoose.model('posts', new Schema({
description: String,
comments: [{type: Schema.Types.ObjectId, ref:'comments'}],
}));
mongoose.model('comments', new Schema({
comment:String,
status: true
}));
If you want to see your friends' posts, you can use this.
Users.find(). //Collection 1
populate({path:'friends', //Collection 2
populate:{path:'posts' //Collection 3
}})
.exec();
If you want to see your friends' posts and also bring all the comments, you can use this and too, you can indentify the collection if this not find and the query is wrong.
Users.find(). //Collection 1
populate({path:'friends', //Collection 2
populate:{path:'posts', //Collection 3
populate:{path:'commets, model:Collection'//Collection 4 and more
}}})
.exec();
And to finish, if you want get only some fields of some Collection, you can use the propiertie select Example:
Users.find().
populate({path:'friends', select:'name status friends'
populate:{path:'comments'
}})
.exec();
MongoDB doesn't have joins, but in your case you can do:
db.coll.find({friends: userId}).sort({age: -1})
one kind of join a query in mongoDB, is ask at one collection for id that match , put ids in a list (idlist) , and do find using on other (or same) collection with $in : idlist
u = db.friends.find({"friends": ? }).toArray()
idlist= []
u.forEach(function(myDoc) { idlist.push(myDoc.id ); } )
db.friends.find({"id": {$in : idlist} } )
Only populate array friends.
User.findOne({ _id: "userId"})
.populate('friends')
.exec((err, user) => {
//do something
});
Result is same like this:
{
"_id" : "userId",
"name" : "John",
"age" : 30,
"friends" : [
{ "_id" : "userId1", "name" : "Derek", "age" : 34 }
{ "_id" : "userId2", "name" : "Homer", "age" : 44 }
{ "_id" : "userId3", "name" : "Bobby", "age" : 12 }
]
}
Same this: Mongoose - using Populate on an array of ObjectId
You can use playOrm to do what you want in one Query(with S-SQL Scalable SQL).
var p = db.sample1.find().limit(2) ,
h = [];
for (var i = 0; i < p.length(); i++)
{
h.push(p[i]['name']);
}
db.sample2.find( { 'doc_name': { $in : h } } );
it works for me.
You can do it in one go using mongo-join-query. Here is how it would look like:
const joinQuery = require("mongo-join-query");
joinQuery(
mongoose.models.User,
{
find: {},
populate: ["friends"],
sort: { age: 1 },
},
(err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);
The result will have your users ordered by age and all of the friends objects embedded.
How does it work?
Behind the scenes mongo-join-query will use your Mongoose schema to determine which models to join and will create an aggregation pipeline that will perform the join and the query.

Resources