Accessing specific values in array of JSON-Objects - ruby-on-rails

I am using rails 3 with backbone.js 0.53 and currently receive a GET with the following array:
[{"credit_card":
{"id":2,"cc_number":"12345678912345","cc_type":"stack","owner":"overflow"}},
....next objects....]
I have read a lot of the other threads but can't figure out how to access the values.
Is there any way to do this with the backbone-given methods like .get()?
I tried
myArray = eval(arrayJSON)
alert myArray.length #works
but any other way of accessing the single values in an array or iterating over it fails.
Probably I am just missing something here.

Quick example of how to iterate through all your results via underscore:
/* received results mocking */
model.attributes = [
{ "credit_card" : { "id":2, "cc_number":"12345678912345" },
{ "credit_card" : { "id":3, "cc_number":"44444444455555" },
{ "credit_card" : { "id":4, "cc_number":"66666655554332" }
]
/* lets get all results */
results = model.toJSON()
/* loop through all results */
_(results).each(item) {
console.log(item.credit_card.id);
}
/* get result by array pos */
console.log(results[1]); // get 2nd item
Cheers

It might be useful to see more details, but in general you should be able to access elements just fine with the following syntax: alert(myArray[0].credit_card.cc_number);
I even pasted your sample array into jsFiddle and had no issues: http://jsfiddle.net/P4w7T/1/

Related

iOS Swit 3 - filter array inside filter

I would like to filter array inside a filter. First I have a big array of Staff object (self.bookingSettings.staffs). Inside this array I have multiple object like this :
"staffs": [
{
"id": 1,
"name": "Brian",
"services": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
},
{
"id": 4
}
],
"pos": 1
},...
I would like to filter this array in order to have only services with id = 3.
I succeed to have if first object is equal to 3 with this code :
self.bookingSettings.staffs.filter({ $0.services.first?.id == self.bookingService.id })
but that takes only the first item.
I think I have to filter inside my filter function, something like this to loop over all object inside services :
self.bookingSettings.staffs.filter({ $0.services.filter({ $0.id == self.bookingService.id }) })
but I've the following error: Cannot convert value of type [BookingService] to closure result type Bool.
Is this a good idea ? How can I achieve this ?
You could use filter, which would look something like this:
self.bookingSettings.staffs.filter {
!$0.services.filter{ $0.id == self.bookingService.id }.isEmpty
}
This code is constructing an entire array of filtered results, only to check if its empty and immediately discard it. Since filter returns all items that match the predicate from the list, it won't stop after it finds a match (which is really what you're looking for). So even if the first element out of a list of a million elements matches, it'll still go on to check 999,999 more elements. If the other 999,999 elements also match, then they will all be copied into filter's result. That's silly, and can use way more CPU and RAM than necessary in this case.
You just need contains(where:):
self.bookingSettings.staffs.filter {
$0.services.contains(where: { $0.id == self.bookingService.id })
}
contains(where:) short-circuits, meaning that it won't keep checking elements after a match is found. It stops and returns true as soon as find a match. It also doesn't both copying matching elements into a new list.

Retrieving "$ref" field in swagger.json

I am trying to use the swagger parser to parse and retrieve information in the "swagger.json" (io.swagger.parser.SwaggerParser;)
Below is an excerpt of the "swagger.json".
I am trying to retrieve "$ref" : "#/definitions/abc".
"responses" : {
"200" : {
"description" : "abc",
"schema" : {
"$ref" : "#/definitions/abc"
}
},
This is the code to parse it.
SwaggerParser sparse = new SwaggerParser();
Swagger swagger = sparse.read("swagger.json");
// This next line is what I am having a problem with.
swagger.getPath("/endpointurl").getGet().getResponses().get("200").getSchema();
At this point, the ".getSchema()" in the above line has only "getType()" in it I can call. It doesn't have "get$ref()". This is because ".getSchema()" returns a "Property" (io.swagger.models.properties.Property). It doesn't have "get$ref()".
get$ref() is available in "RefProperty" (io.swagger.models.properties.RefProperty)
But ".getSchema()" doesn't return a "RefProperty".
Typecast the result of ".getSchema()" to a "RefProperty" also doesn't work. It ends up in this error.
java.lang.ClassCastException: io.swagger.models.properties.ArrayProperty cannot be cast to io.swagger.models.properties.RefProperty
Has anyone tried parsing a "swagger.json" and was able to retrieve the "$ref": line under "schema" in the "response" block?
Any idea how might I be able to do that?
I figured out a way to do that. Maybe not the best way to do it, but it retrieves the information in "#ref".
Object obj = xxxxx.getSchema(); // xxxxx is whatever your code that gives you ".getSchema()". Mine is in a map and I don't want to distract people.
ArrayProperty arrProp = new ArrayProperty();
arrProp = (ArrayProperty)obj; // .getSchema() returns an ArrayProperty
RefProperty refProperty = (RefProperty) arrProp.getItems(); // .getItems() will return the RefProperty type you need to call ".get$ref()".
String refStr = refProperty.get$ref(); // Voila, there's your content in "#ref".
String simpleRefStr = refProperty.getSimpleRef();
I had to do a few type castings. If you have a more elegant way of doing this, please post here.

Modifying NSMutableDictionary by key path

I have a NSDictionary with nested NSDictionary/NSArray (Generated through a JSON).
I need to remove objects in multiple places according to some logic imposed on me.
For instance lets say that the dictionary has some structure like:
{
"Array1" : [
{
"InnerArray1" : [
{
"some conditional field" : Evaluate this ...
}
],
"More Properties : ....
}
],
"Array2" : {
... some complex inner structure
{
// some inner object to remove according to "evaluate condition"
}
}
}
When I iterate the "Array1.InnerArray1..." and evaluate some condition to true , I need to remove objects in a disjoint location.
Ideally I could do something like
foreach item in Array1.InnerArray1 {
if item evaluates to true {
// evaluate the disjoint location...
remove Array2.....InnerObject(s) where ConditionField == true
}
}
Currently it is very awkward to iterate the inner objects and mutate them on the same pass (and very hard to read).
Given I have created a deep mutable copy of this whole data tree, is it possible to remove nested objects using kvc or another mechanism without nested iterations?

Mongoid max and embeded collections

I have a Collection Report embeds submissions
class Report
embeds_many :submissions
class Submission
embedded_in :report
field :date_submitted, type: TimeWithZone
field :mistakes, type: Integer
I am trying to create a scope on Report
I want to add a scope query with two parts
get the latest submission (given by max date_submitted) that also has zero mistakes
I can create a scope for the mistakes part, but cannot work out how to get the latest submission
scope :my_scope, where("submissions.mistakes" => 0)
So this report would be returned as it's last enter in submissions has zero mistakes
Report
"submissions" : [
{
"date_submitted" : ISODate("2014-01-28T13:00:00Z"),
"mistakes" : 11
},
{
"date_submitted" : ISODate("2014-03-08T13:00:00Z"),
"mistakes" : 0
}
]
where this one wouldn't be returned
Report
"submissions" : [
{
"date_submitted" : ISODate("2014-01-28T13:00:00Z"),
"mistakes" : 0
},
{
"date_submitted" : ISODate("2014-03-08T13:00:00Z"),
"mistakes" : 11
}
]
This is because you are not filtering the element of the embedded array but the document that contains that element.
There could be an $elemMatch clause here which allows you to combine the conditions on a single element. But find does not have any operation for getting the max value as it were. This is not to be confused with the $max query modifier, which actually clips the index in use to not search beyond those bounds.
So here you use aggregate:
db.collection.aggregate([
// Optionally query to match and filter your documents.
//{ "$match: { /* Same conditions as find */ } },
// Unwind the array
{ "$unwind": "$submissions" },
// Filter all but 0 mistakes
{ "$match": { "submissions.mistakes": 0 } },
// Group the results, taking the max entry and presuming by document `_id`
{ "$group": {
"_id": "$_id",
"date_submitted": { "$max": "$submissions.date_submitted" }
}}
])
That is the general process for filtering the elements of an array. You may look into your driver implementation of aggregate, but the form is always the pipeline represented as an array of documents (hashes) in this form. Possibly using the moped form for getting the collection method. So something like:
Report.collection.aggregate([ /* stages */ ])
For more information on returning the original document form if that is what your requirement is then see here.

Update field of embedded documents on multiple Mongoid documents [duplicate]

This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 5 years ago.
I recently started using MongoDB and I have a question regarding updating arrays in a document.
I got structure like this:
{
"_id" : ObjectId(),
"post" : "",
"comments" : [
{
"user" : "test",
"avatar" : "/static/avatars/asd.jpg",
"text" : "....."
}
{
"user" : "test",
"avatar" : "/static/avatars/asd.jpg",
"text" : "....."
}
{
"user" : "test",
"avatar" : "/static/avatars/asd.jpg",
"text" : "....."
}
...
]
}
I'm trying to execute the following query:
update({"comments.user":"test"},{$set:{"comments.$.avatar": "new_avatar.jpg"}},false,true)
The problem is that it update all documents, but it update only the first array element in every document. Is there any way to update all array elements or I should try to do it manually?
Thanks.
You cannot modify multiple array elements in a single update operation. Thus, you'll have to repeat the update in order to migrate documents which need multiple array elements to be modified. You can do this by iterating through each document in the collection, repeatedly applying an update with $elemMatch until the document has all of its relevant comments replaced, e.g.:
db.collection.find().forEach( function(doc) {
do {
db.collection.update({_id: doc._id,
comments:{$elemMatch:{user:"test",
avatar:{$ne:"new_avatar.jpg"}}}},
{$set:{"comments.$.avatar":"new_avatar.jpg"}});
} while (db.getPrevError().n != 0);
})
Note that if efficiency of this operation is a requirement for your application, you should normalize your schema such that the location of the user's avatar is stored in a single document, rather than in every comment.
One solution could be creating a function to be used with a forEach and evaling it (so it runs quickly). Assuming your collection is "article", you could run the following:
var runUpdate = function(){
db.article.find({"comments.user":"test").forEach( function(article) {
for(var i in article.comments){
article.comments[i].avatar = 'new_avatar.jpg';
}
db.article.save(article);
});
};
db.eval(runUpdate);
If you know the indexes you want to update you can do this with no problems like this:
var update = { $set: {} };
for (var i = 0; i < indexesToUpdate.length; ++i) {
update.$set[`comments.${indexesToUpdate[i]}. avatar`] = "new_avatar.jpg";
}
Comments.update({ "comments.user":"test" }, update, function(error) {
// ...
});
be aware that must of the IDE's will not accept the syntax but you can ignore it.
It seems like you can do this:
db.yourCollection.update({"comments.user":"test"},{$set:{"comments.0.avatar": "new_avatar.jpg", "comments.1.avatar": "new_avatar.jpg", etc...})
So if you have a small known number of array elements, this might be a little easier to do. If you want something like "comments.*.avatar" - not sure how to do that. It is probably not that good that you have so much data duplication tho..

Resources