Firebase Query for a specific value [duplicate] - swift

Given the data structure below in firebase, i want to run a query to retrieve the blog 'efg'. I don't know the user id at this point.
{Users :
"1234567": {
name: 'Bob',
blogs: {
'abc':{..},
'zyx':{..}
}
},
"7654321": {
name: 'Frank',
blogs: {
'efg':{..},
'hij':{..}
}
}
}

The Firebase API only allows you to filter children one level deep (or with a known path) with its orderByChild and equalTo methods.
So without modifying/expanding your current data structure that just leaves the option to retrieve all data and filter it client-side:
var ref = firebase.database().ref('Users');
ref.once('value', function(snapshot) {
snapshot.forEach(function(userSnapshot) {
var blogs = userSnapshot.val().blogs;
var daBlog = blogs['efg'];
});
});
This is of course highly inefficient and won't scale when you have a non-trivial number of users/blogs.
So the common solution to that is to a so-called index to your tree that maps the key that you are looking for to the path where it resides:
{Blogs:
"abc": "1234567",
"zyx": "1234567",
"efg": "7654321",
"hij": "7654321"
}
Then you can quickly access the blog using:
var ref = firebase.database().ref();
ref.child('Blogs/efg').once('value', function(snapshot) {
var user = snapshot.val();
ref.child('Blogs/'+user+'/blogs').once('value', function(blogSnapshot) {
var daBlog = blogSnapshot.val();
});
});
You might also want to reconsider if you can restructure your data to better fit your use-case and Firebase's limitations. They have some good documentation on structuring your data, but the most important one for people new to NoSQL/hierarchical databases seems to be "avoid building nests".
Also see my answer on Firebase query if child of child contains a value for a good example. I'd also recommend reading about many-to-many relationships in Firebase, and this article on general NoSQL data modeling.

Given your current data structure you can retrieve the User that contains the blog post you are looking for.
const db = firebase.database()
const usersRef = db.ref('users')
const query = usersRef.orderByChild('blogs/efg').limitToLast(1)
query.once('value').then((ss) => {
console.log(ss.val()) //=> { '7654321': { blogs: {...}}}
})
You need to use limitToLast since Objects are sorted last when using orderByChild docs.

It's actually super easy - just use foreslash:
db.ref('Users').child("userid/name")
db.ref('Users').child("userid/blogs")
db.ref('Users').child("userid/blogs/abc")
No need of loops or anything more.

Related

Fetch a random record from a Realm database (Swift)

I am trying to fetch a random record from my Swift Realm database.
I have previously used the sample function in mongoDB, so I thought there must be an equivalent in Realm (it's based on mongoDB, right?)
I can't find any documentation on such a function, and I've only found search results which suggest to fetch the entire collection then choose a random record [1, 2]. Obviously, this is inefficient.
Am I missing something obvious, is there a better way to do it?
See below for an example mongoDB query:
db.Words.aggregate([
{ $match: { gender: gender } },
{ $sample: { size: 1 } }
])
For clarity the code in the question is not part of the Realm Swift SDK for local or sync but it is a query directly to Atlas using app services, so it would be valid for non-sync'ing or non-local applications. (Use the Swift SDK if possible!)
If we're doing this using the SDK, you can actually leverage high-level Swift functions to return a result using .randomElement()
So given a PersonClass that has a name property
class PersonClass: Object {
#Persisted var name = ""
}
we can this use this code to return a random person from Realm and output their name to console
if let randomPerson = realm.objects(PersonClass.self).randomElement() {
print(randomPerson.name)
} else {
print("no data was returned)")
}

Mongodb Ref dynamic populate with grapqhl?

I have to decide whether to populate or not according to the query request, but I don't know how to do it.
So Example
If my model User is looks like this
below syntax is from typegoose and typegraphql
class User {
#Field()
#prop()
name: string;
#Field()
#prop(ref:"House")
house: Ref<House>
}
And here is two diffent query
Query1
user {
name
}
Query2
user {
name
house {
location
}
}
And in the resolver
User: () => {
const user = UserModel.find(blahblah)**.populate("house")**
return user
}
Query1 dose not need populate
but Query2 need
in same resolver!
I want to decide whether to populate or not depending on the requirements of the query.
I can't decide whether to populate or not without knowing what is the actual query was in resolver.
I found very similar question in stackoverflow
But there is not proper answer...
Solving relationships in Mongoose and GraphQL
i dont know much about graphql, but i think there is some method to get if that path is requested, so the following should work:
let query = Model.find(basicQuery);
if (req.path) { // replace this with graphql's method to get if the path is requested
query = query.populate(yourPath);
}
const doc = await query.exec();
PS: but as an comment already noted, i think there is some better method to do this in graphql (another resolver?)

Meteorjs - What is the proper way to join collections on backend

I am very new to meteor.js and try to build an application with it. This time I wanted to try it over MEAN stack but at this point I am struggled to understand how to join two collection on server side...
I want very identical behaviour like mongodb populate to fetch some properties of inner document.
Let me tell you about my collection it is something like this
{
name: 'Name',
lastName: 'LastName',
anotherObject: '_id of another object'
}
and another object has some fields
{
neededField1: 'asd',
neededField2: 'zxc',
notNeededField: 'qwe'
}
So whenever I made a REST call to retrieve the first object I want it contains only neededFields of inner object so I need join them at backend but I cannot find a proper way to do it.
So far while searching it I saw some packages here is the list
Meteor Collections Helper
Publish with Relations
Reactive joins in Meteor (article)
Joins in Meteor.js (article)
Meteor Publish Composite
You will find the reywood:publish-composite useful for "joining" related collections even though SQL-like joins are not really practical in Mongo and Meteor. What you'll end up with is the appropriate documents and fields from each collection.
Using myCollection and otherCollection as pseudonyms for your two collections:
Meteor.publishComposite('pseudoJoin', {
find: function() {
return myCollection.find();
},
children: [
{
find: function(doc) {
return otherCollection.find(
{ _id: post.anotherObject },
{ fields: { neededField1: 1, neededField2: 1 } });
}
}
]
});
Note that the _id field of the otherCollection will be included automatically even though it isn't in the list of fields.
Update based on comments
Since you're only looking to return data to a REST call you don't have to worry about cursors or reactivity.
var myArray = myCollection.find().fetch();
var myOtherObject = {};
var joinedArray = myArray.map(function(el){
myOtherObject = otherCollection.findOne({ _id: el.anotherObject });
return {
_id: el._id,
name: el.name,
lastName: el.lastName,
neededField1: myOtherObject.neededField1,
neededField2: myOtherObject.neededField2
}
});
console.log(joinedArray); // These should be the droids you're looking for
This is based on a 1:1 relation. If there are many related objects then you have to repeat the parent object to the number of children.

Backbone.js cascading collections and sync?

I'm trying to use as much of the OOTB sync and RESTful functionality in Backbone. I have a Web API set up for basic CRUD for my models. I have:
var SearchModel = Backbone.Model.extend({});
var SearchMappingModel = Backbone.Model.extend({});
var SearchComponentModel = Backbone.Model.extend({});
var SearchCollection = Backbone.Collection.extend({});
var SearchMappingCollection = Backbone.Collection.extend({});
var SearchComponentCollection = Backbone.Collection.extend({});
For every Search there is 1-to-many SearchMappings, and for every SearchMapping, there are 1-to-many SearchComponents. My URLs for sync would be something like, "/search" for the Search collection, "'/searchmapping/' + searchId" for the SearchMapping collection, and "'/searchcomponent/' + mappingId" for the SearchComponent collection.
My question is, since each collection is dependent on the previous one, is there a way I can make a cascading relationship in backbone to minimize my code and use as much of the basic sync functionality that's already there?
My initial thought is to create a collection within a collection and write my own .fetch() to first fetch the parent collection and on its success then fetch the child, which will then also get its child after its own success, like this:
var SearchCollection = Backbone.Collection.extend({
model: SearchModel,
initialize: function (data) {
this.url = baseURL + "/search";
this.data = data;
this.SearchMappingCollection = new SearchMappingCollection();
},
fetchData: function () {
this.fetch({
success: _.bind(function (results) {
this.fetchListSuccess(results);
}, this)
});
},
fetchListSuccess: function (results) {
this.SearchMappingCollection.fetchData(results);
}
The same would be done on a .save(). This may be a good way of doing it, but wanted to get feedback from anyone else that's done something similar.
I ended up not using a cascading format. It seems that it was adding more complexity and giving nothing in return. All 3 collections now sit on the controller level, and I just load the next collection after each collection is loaded on each "reset" event.

How to design a REST search with backbone

I'm designing an API and also consuming it with Backbone.js. Part of the API will include search operations. For example when searching for cars, I might have something like:
http://api.mysite.com/search/cars?q=volvo
With backbone, I can see two options for consuming the results.
Option 1: A search is a Collection
var CarSearch = Backbone.Collection.extend({
model: Car,
initialize : function(models, options){
this.query = options.query;
},
url: function(){
return "http://api.mysite.com/search/cars?q="+this.query;
}
});
var volvos = new CarSearch([], {query:'volvo'});
volvos.fetch();
Option 2: A search is a Model, and the results are a Collection
var CarSearchResults = Backbone.Collection.extend({
model: Car
});
var CarSearch = Backbone.Model.extend({
defaults: {
"query":"",
"carSearchResults":null
},
url: function(){
return "http://api.mysite.com/search/cars?q="+this.get('query');
},
parse: function(resp,xhr){
resp.carSearchResults = new CarSearchResults(resp.carSearchResults);
return resp;
}
});
var volvoSearch = new CarSearch();
volvoSearch.set({query:'volvo'});
volvoSearch.save();
What are the advantages / disadvantages of these options? Is there a backbone-y way of designing this?
I'm leaning towards option 2 because it seems easier to add things to the response like pagination details, or a next url. But option 2 seems messier in a couple of ways. For example, would I generate an ID on the server for the search model when it is saved? Don't think I need to get that model by ID, deleting or updating it doesn't really make sense either cause I'm not persisting it.
i dont know if its a good practice,
but i use for my search the "data" option in the "fetch" method.
https://stackoverflow.com/a/6659501/1067061
Maybe it helps.
Good Luck!
EDIT
This is the right way to pass query parameters in your collections url,
The reference to the Docs shows how to pass the data attribute in fetch options, the data attribute is actually an object with key value pairs referring to query params and their values
I would go with option one. At least imo a model should correspond to a single search result and the collection to the entire set of search results. so if you search for volvo and there are 6 items returned, each item should be a model contained within your collection.
Now this will largely depend on how you are representing a result on your server. If say for instance you have car instances then you just do the search server side using the query and return the resulting objects as json. Then you can have the returned list be the collection of car models that match the criteria. but if you are planning on returning the query results some other way then you will have to think about how the model should represent the data
I would recommend using a collection, like in option 1, but without the need to define a new collection just for the search.
Take a look at my blog post about this here: http://willdemaine.ghost.io/restful-search-with-backbone/
var SearchableCollection = Backbone.Collection.extend({},{
search: function(query, options){
var search = $.Deferred();
options = options || {};
var collection = new this([], options);
collection.url = _.result(collection, 'url') + 'search?q=' + query;
var fetch = collection.fetch();
fetch.done(_.bind(function(){
Backbone.Events.trigger('search:done');
search.resolveWith(this, [collection]);
}, this));
fetch.fail(function(){
Backbone.Events.trigger('search:fail');
search.reject();
});
return search.promise();
}
});
Then you can do:
var Cars = SearchableCollection.extend({});
var findCars = Cars.search('volvo');
findCars.done(function(cars){
var carsView = new CarsView({
collection: cars
});
carsView.render();
});