I've installed SwiftMongoDB using CocoaPods. Added 2 documents in the collection. When I try to retrieve them using .find() method It only returns one document.
func all() -> [MongoDocument]{
let UsersCollection = MongoCollection(name: "users")
mongodb?.mongodb.registerCollection(UsersCollection)
for (index,value) in UsersCollection.find().successValue!.enumerate(){
debugPrint(value)
}
// UsersCollection.find().successValue!.count
// returns 1.
return UsersCollection.find().successValue!
}
My collection looks like:
{ "_id" : ObjectId("56bb29ca42b9b41900000000"), "address" : "US", "given" : "User", "birthDate" : "1985-08-01", "family" : "UserFam", "identifier" : "E3826", "date" : "10.2.2016 at 14:15:6" }{ "_id" : ObjectId("56bb29ca42b9b41900000000"), "address" : "US", "given" : "User2", "birthDate" : "1985-08-01", "family" : "UserFam2", "identifier" : "E3826", "date" : "10.2.2016 at 14:15:6" }
Is there another way of getting all the documents? Am I doing something wrong?
I have never used SwiftMongoDB but I have used swift for iOS development and mongoDB with Java. First of all, here is your first object's and your second object's ids together:
1st: 56bb29ca42b9b41900000000
2nd: 56bb29ca42b9b41900000000
As you can see they are the same. So I strongly believe your issue arises from that. Have you defined that property as primary key?
This is a bug. Maybe the package is in it's early versions ....
Related
I am currently trying to figure out if CouchDB is suitable for my use-case and if so, how. I have a situation similar to the following:
First set of documents (let's call them companies):
{
"_id" : 1,
"name" : "Foo"
}
{
"_id" : 2,
"name" : "Bar"
}
{
"_id" : 3,
"name" : "Baz"
}
Second set of documents (let's call them projects):
{
"_id" : 4,
"name" : "FooProject1",
"company" : 1
}
{
"_id" : 5,
"name" : "FooProject2",
"company" : 1
}
...
{
"_id" : 100,
"name" : "BazProject2",
"company" : 3
}
Third set of documents (let's call them incidents):
{
"_id" : "300",
"project" : 4,
"description" : "...",
"cost" : 200
}
{
"_id" : "301",
"project" : 4,
"description" : "...",
"cost" : 400
}
{
"_id" : "302",
"project" : 4,
"description" : "...",
"cost" : 500
}
...
So in short every company has multiple projects, and every project can have multiple incidents. One reason I model the data is, that I come mainly from a SQL background, so the modelling may be completely unsuitable. The second reason is, that I would like to add new incidents very easily by just using the REST-API provided by couchdb. So the incidents have to be single documents.
However, I now would like to get a view that would allow me to calculate the total cost for each company. I can easily define a view using map-reduce and linked documents which get's me the total amount per project. However once I am at the project level I cannot get any further to the level of the company.
Is this possible at all using couchDb? This kind of summarising data sounds like a perfect use case for map-reduce. In SQL I would just do a three-table join, but it seems like in couchDb the best I can get is two-table joins.
As mentioned you cannot do joins in CouchDb but this isn't a limitation, this is an invitation to both think about your problems and approach them differently. The correct way to do this in CouchDb is to define data structures called for example : IncidentReference composed of :
The project id
And the company id
That way your data would look like :
{
"_id" : "301",
"project" : 4,
"description" : "...",
"cost" : 400,
"reference" : {
"projectId" : 1,
"companyId" : 2
}
}
This is just fine. Once you have that, you can play with Map/Reduce to achieve whatever you want easily. Generally speaking, you need to think about the way you are going to query your data.
I'm currently trying to setup a friendslist relationship using Firebase and I'm experiencing some issues with the process of adding a friend for a user.
I currently have a schema like this:
users
-----
UID
->Name
->Friendslist
->UID of friend:true
userDisplays
------------
-Users Name:Users UID
addedFriends
------------
-UID of added user
->UID Of user that did the adding
My idea of adding a friend is using the name of the user and looking them up in the userDisplays tree, that lookup seems to work everytime. However, when I then try to read the uid value from the child in userDisplays it will sometimes return NULL, or will skip the adding entirely after it finds the uid value (by this I mean it will not add the uid to the adding user and not create a addedFriends child).
The same issue is when the adding user successfully adds the desired user and a addedFriends child is created linking the two, but again when the added user checks for recent addings and is given the option to 'add back' it will return NULL or skip the removal of the addedFriends child and not add the uid to the users list of friends.
I tried to copy the relationship example found in the docs, but I'm confused on where I am missing things, or if this is expected behavior?
Here is my structure after two users have been created. Before a friends list has been created.
{
"userDisplays" : {
"a" : "fed7738e-7dec-4ff3-9cc9-46dee3c189e6",
"t" : "c3b27833-d56b-40e9-b46f-c99128193f3d"
},
"users" : {
"c3b27833-d56b-40e9-b46f-c99128193f3d" : {
"displayName" : "t",
"email" : "test#test.com",
"provider" : "password"
},
"fed7738e-7dec-4ff3-9cc9-46dee3c189e6" : {
"displayName" : "a",
"email" : "test2#test.com",
"provider" : "password"
}
}
}
This is the swift code I'm using to perform the adding of a friend given a user name:
ref.userDisplayBaseSingleton.childByAppendingPath("/\(userName)").observeSingleEventOfType(.Value, withBlock: { snapshot in
if snapshot.value is NSNull{
print("null")
}else{
print(snapshot.value)
print("found val")
ref.userBaseSingleton.childByAppendingPath(snapshot.value as! String).observeSingleEventOfType(.Value, withBlock: { (snap) in
let friendData = [
snap.key:true
]
ref.userBaseSingleton.childByAppendingPath("\(currentUser!.id!)/friends").updateChildValues(friendData)
let currentAddData = [
snap.key:currentUser!.id!
]
let friendAddRef = ref.addBaseSingleton.childByAutoId()
friendAddRef.setValue(currentAddData)
})
}
})
Basically the issues I'm experiencing from this snippet is that sometimes the look up from userDisplays doesn't return a value, or if it does it doesn't add a addedFriends node. I've experienced a bug when retrying adding the username again, but it will actually generate a new uid of the users and then generate a new addedFriends child.
For example, if I was user t and I tried to add a a few kinds of behavior can happen.
userDisplay for a returns null
userDisplay returns a and returns a's uid but the addedFriends node isn't generated
a is properly added, and an addedFriends node is generated, however when user a is notified of the add and is given the option to add back t it seems to reproduce the same kind of errors.
I've noticed that after a period of time, the actual uid of t will update on the firebase and then the add will be successful. By this I mean that the initial uid that t is assigned will change and then I've noticed the code above will work. I'm also assuming the reason why its updated has to do with the errors thats happening, but I could be wrong.
Heres a snippet of the error happening
}
{
"addedFriends" : {
"-KH6pR5TV7vjVeADc7mc" : {
"22a3c5fa-e578-4ada-b3c1-355add80041e" : "098804cd-1ffa-4508-b353-6f6a4377661f"
}
},
"userDisplays" : {
"test" : "f0bb77a9-8156-4d44-ad74-6d6b01765802",
"test2" : "098804cd-1ffa-4508-b353-6f6a4377661f"
},
"users" : {
"098804cd-1ffa-4508-b353-6f6a4377661f" : {
"displayName" : "test2",
"email" : "test2#test.com",
"friends" : {
"22a3c5fa-e578-4ada-b3c1-355add80041e" : true
},
"provider" : "password"
},
"f0bb77a9-8156-4d44-ad74-6d6b01765802" : {
"displayName" : "test",
"email" : "test#test.com",
"provider" : "password"
}
}
}
I am trying to make a query to a Firebase collection using swift.
My Collection is like this :
{
"networks" : {
"-KF9zQYGA1r_JiFam8gd" : {
"category" : "friends",
"members" : {
"facebook:10154023600052295" : true
},
"name" : "My friends",
"owner" : "facebook:10154023600052295",
"picture" : "https://my.img/img.png"
},
"-KF9zQYZX6p_ra34DTGh" : {
"category" : "friends",
"members" : {
"tototata" : true
},
"name" : "My friends2",
"owner" : "facebook:10154023600052295",
"picture" : "https://my.img/img.png"
}
}
and my query is like that :
let networksRef = ref.childByAppendingPath("networks")
.queryOrderedByChild("members")
.queryEqualToValue(true, childKey: uid)
Then I am populating a TableView using FirebaseUI.
the thing is that query doesn't return anything, I also tried using this kind of query :
let networksRef = ref.childByAppendingPath("networks")
.queryOrderedByChild("members")
.queryStartingAtValue(true, childKey: uid)
.queryEndingAtValue(true, childKey: uid)
And to be clear "uid" is the node name nested in the "members" node with true as value. (As on the picture)
I can't get all the nodes without filtering because of the amount of data to be downloaded.
I'm stuck on that for a day, and I'm going crazy.. :-)
If someone can help ?
The correct syntax would be:
let networksRef = ref.childByAppendingPath("networks")
.queryOrderedByChild("members/\(uid)")
.queryEqualToValue(true)
But note that you'll need an index for each uid for this to work efficiently:
{
"rules": {
"networks": {
".indexOn": ["facebook:10154023600052295", "tototata"]
}
}
}
Without these indexes, the Firebase client will download all data and do the filtering locally. The result will be the same, but it'll consume a lot of unneeded bandwidth.
A proper solution for this requires that you change your data structure around. In Firebase (and most other NoSQL databases) you often end up modeling the data in the way that your application wants to access it. Since you are looking for the networks that a user is part of, you should store the networks per user:
"networks_per_uid": {
"facebook:10154023600052295": {
"-KF9zQYGA1r_JiFam8gd": true
},
"tototata": {
"-KF9zQYZX6p_ra34DTGh": true
},
}
Adding this so-called index to your data structure is called denormalizing and is introduces in this blog post, the documentation on data structuring and this great article about NoSQL data modeling.
When using the IOS API, I'm making a call to connect via the ApigeeDataClient connectEntities method. I pass in the type "users", then the user's uuid, then connectionType "likes", with the connectee type of "songs" and the song's uuid.
Example:
ApigeeClientResponse *response = [_dataClient connectEntities:#"users" connectorID:_apigeeUser.uuid connectionType:#"likes" connecteeType:#"songs" connecteeID:song.uuid];
When I make the connection, it says successful, but when I look at the data on the server, it seems to save the connection incorrectly. For example, for the song, I see:
connecting :likes :/songs/b523a6aa-bb39-11e4-a2bb-35673af856e9/connecting/likes
It looks like the song's uuid isn't in the connecting path.
The same is true for the connection related to the user. It's the user's uuid that seems to be connected to the same user. The uuid is that of the song's uuid, not the user's. When I make the call to getEntityConnections, like so:
ApigeeClientResponse *response = [_dataClient getEntityConnections:#"songs" connectorID:_apigeeUser.uuid connectionType:#"likes" query:nil];
It returns an error, saying "expected song, but got user's uuid.
Entity c831e1c4-2e6e-11e4-94ce-299efa8c6fd5 is not the expected type, expected song, found user"
In looking in Apigee itself, in the data section, I see the following snippet:
"connections": {
"likes": "/users/c831e1c4-2e6e-11e4-94ce-299efa8c6fd5/likes"
}
The song's uuid is missing. Even when I try to update the JSON directly on the server, basically adding the song's uuid to the end, it says it's saved, but it removes the song's uuid.
Even just using the curl method to make a connection doesn't work. For example:
curl -X POST http://api.usergrid.com/peterdj/sandbox/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes/c37f1eaa-bfa3-11e4-9141-97b3510c98e6
When I make that call, I get this
{"action":"post",
"application":"0baaf590-2c1b-11e4-9bb5-11cb139f1620",
"params":{
},
"path":"/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes",
"uri":"https://api.usergrid.com/peterdj/sandbox/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes",
"entities":[
{
"uuid":"c37f1eaa-bfa3-11e4-9141-97b3510c98e6",
"type":"song",
"name":"WingSpan",
"created":1425167080842,
"modified":1425167080842,
"bpm":"124",
"code":"WingSpan",
"genre":"Progressive House",
"metadata":{
"connecting":{
"likes":"/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes/c37f1eaa-bfa3-11e4-9141-97b3510c98e6/connecting/likes"
},
"path":"/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes/c37f1eaa-bfa3-11e4-9141-97b3510c98e6"
},
"title":"Wing Span"
}
],
"timestamp":1425246006718,
"duration":78,
"organization":"peterdj",
"applicationName":"sandbox"
}
Notice that the resulting connecting path seems correct when it's returned, but when do another GET curl, as so:
curl http://api.usergrid.com/peterdj/sandbox/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d
The song's uuid isn't there:
{
"action" : "get",
"application" : "0baaf590-2c1b-11e4-9bb5-11cb139f1620",
"params" : { },
"path" : "/users",
"uri" : "https://api.usergrid.com/peterdj/sandbox/users",
"entities" : [ {
"uuid" : "bc2fc82a-bfa3-11e4-a994-b19963f1779d",
"type" : "user",
"name" : "peter",
"created" : 1425167068578,
"modified" : 1425167495412,
"username" : "peterdj",
"email" : "asdf#adf.com",
"activated" : true,
"picture" :"",
"metadata" : {
"path" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d",
"sets" : {
"rolenames" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/roles",
"permissions" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/permissions"
},
"connections" : {
"likes" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/likes"
},
"collections" : {
"activities" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/activities",
"devices" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/devices",
"feed" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/feed",
"groups" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/groups",
"roles" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/roles",
"following" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/following",
"followers" : "/users/bc2fc82a-bfa3-11e4-a994-b19963f1779d/followers"
}
}
} ],
"timestamp" : 1425311662762,
"duration" : 12,
"organization" : "peterdj",
"applicationName" : "sandbox"
}
Is this a bug with the entity connections with Apigee/Usergrid or am I doing something wrong?
Thanks
Well, turns out, thanks to the comments by #remus, I've figured it out.
In this call:
ApigeeClientResponse *response = [_dataClient getEntityConnections:#"songs" connectorID:_apigeeUser.uuid connectionType:#"likes" query:nil];
The connection needs to be "users", not "songs". Works now. Thanks #remus
I have this simple model:
abstract class Info {
ObjectId id
Date dateCreated
Date lastUpdated
}
class Question extends Info {
String title
String content
List<Answer> answers = []
static embedded = ['answers']
}
class Answer {
String content
}
Written this way, answer are embedded in question (and no id is maintained for answer). I want to maintain the id, dateCreated, and lastUpdated fields for every answer. So I try the following:
class Answer extends Info {
String content
}
When I run a simple test case (save a question with 1 answer), I get the following:
> db.question.find()
{ "_id" : ObjectId("4ed81d47e4b0777d795ce3c4"), "answers" : [ { "content" : "its very
cool", "dateCreated" : null, "lastUpdated" : null, "version" : null } ], "content" :
"whats up with mongodb?", "dateCreated" : ISODate("2011-12-02T00:35:19.303Z"),
"lastUpdated" : ISODate("2011-12-02T00:35:19.303Z"), "title" : "first question",
"version" : 0 }
I notice here that fields dateCreated and lastUpdate are not auto-maintained by Grails. Also version field was added but has a null value as well, but interestingly no _id field created (even if I defined id in Info class).
In a second scenario, I try this:
class Answer {
ObjectId id
String content
}
and I get the following output:
> db.question.find()
{ "_id" : ObjectId("4ed81c30e4b076cb80ec947d"), "answers" : [ { "content" : "its very
cool" } ], "content" : "whats up with mongodb?", "dateCreated" : ISODate("2011-12-
02T00:30:40.233Z"), "lastUpdated" : ISODate("2011-12-02T00:30:40.233Z"), "title" :
"first question", "version" : 0 }
This time, id is also not created for the embedded document. Any explanation for this scenarios ? Why there is no id property, and why dateCreated, lastUpdated, and version are null? Is this intended to work this way, or is it a bug?
Thank you,
this is probably due to how the grails framework does the conversion (the GORM module).
You may have quicker / better answers from the grails forum.
Basically it seems that some of the automatic behavior (fill in dates and objectid) is only done for the root object, not subobjects.
You can also checkout an alternative ORM based on morphia:
http://www.grails.org/plugin/mongodb-morphia