I am experimenting with Dojo, using a DataGrid/JsonRestStore against a REST-service implemented using Django/tastypie.
It seems that the JsonRestStore expects the data to arrive as a pure array, whilst tastypie returns the dataset within a structure containing "schema" and "objects".
{
"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1},
"objects": [{...}]
}
So, what I need is to somehow attach to the "objects" part.
What is the most sensible way to achieve this ?
Oyvind
Untested, but you might try creating a custom store that inherits from JsonRestStore and override the internal _processResults method. It's a two-liner in the Dojo 1.7 code base, so you can implement you own behavior quite simply.
_processResults: function(results, deferred){
var count = results.objects.length;
return {totalCount: deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results.objects};
}
See lines 414-417 of the dojox/data/JsonRestStore.js for reference.
I don't know whether this will helpful for you or not. http://jayapal-d.blogspot.in/2009/08/dojo-datagrid-with-editable-cells-in.html
Related
I have an application that is split into a backend and a desktop app. The exchange between them takes place by sending requests in json format and everything functions normally until the backend changes are made concerning the object model itself (for json, a specific key is added or removed).
Here is an example of one of the models (from the desktop app side):
void from_json(const nlohmann::json &json, CaseModel &model)
{
from_json(json, (BasicModel&)model);
crm::json_extract(model.office, json.at("office"));
crm::json_extract(model.cid, json.at("cid"));
crm::json_extract(model.commentary, json.at("commentary"));
crm::json_extract(model.date_received, json.at("date_received"));
crm::json_extract(model.purchases, json.at("purchases"));
crm::json_extract(model.purchases, json.at("payments"));
crm::json_extract(model.researches, json.at("researches"));
crm::json_extract(model.participants, json.at("participants"));
crm::json_extract(model.departments, json.at("related_departments"));
crm::json_extract(model.experts, json.at("related_experts"));
crm::json_extract(model.managers, json.at("related_managers"));
crm::json_extract(model.lawyers, json.at("related_lawyers"));
crm::json_extract(model.collectors, json.at("related_collectors"));
crm::json_extract(model.courriers, json.at("related_courriers"));
crm::json_extract(model.attachments, json.at("attachments"));
crm::json_extract(model.resolution, json.at("resolution"));
}
void to_json(nlohmann::json &json, const CaseModel &model)
{
to_json(json, (const BasicModel&)model);
json["office"] = crm::json_dump(model.office);
json["cid"] = crm::json_dump(model.cid);
json["commentary"] = crm::json_dump(model.commentary);
json["date_received"] = crm::json_dump(model.date_received);
json["purchases"] = crm::json_dump(model.purchases);
json["researches"] = crm::json_dump(model.researches);
json["payments"] = crm::json_dump(model.payments);
json["participants"] = crm::json_dump(model.participants);
json["related_departments"] = crm::json_dump(model.departments);
json["related_experts"] = crm::json_dump(model.experts);
json["related_managers"] = crm::json_dump(model.managers);
json["related_lawyers"] = crm::json_dump(model.lawyers);
json["related_collectors"] = crm::json_dump(model.collectors);
json["related_courriers"] = crm::json_dump(model.courriers);
json["attachments"] = crm::json_dump(model.attachments);
json["resolution"] = crm::json_dump((long int)model.resolution);
}
Here's json itself:
{
"result": [
{
"related_departments": [],
"related_experts": [],
"related_managers": [],
"related_lawyers": [],
"related_courriers": [],
"related_collectors": [],
"courtcase": null,
"contractcase": null,
"arbitragecase": null,
"id": 13,
"resolution": 1,
"date_sent_lawyer": null,
"office": 1,
"cid": "test case cid",
"commentary": "",
"date_received": "2021-11-08T12:20:39.337Z",
"purchases": [],
"researches": [],
"participants": [],
"attachments": [],
"payments": [
{
"pk": 1
}
]
}
]
}
Here is a unit test:
#include <gtest/gtest.h>
#include <nlohmann/json.hpp>
#include <glibmm/datetime.h>
#include <glibmm/ustring.h>
#include "Utility/Concepts.hpp"
#include "Database/Models/CaseModel.hpp"
#include "CaseModel_test.hpp"
template<typename T>
concept HasNeededProperties = requires(T model) {
typename T::Property;
T::Property::id;
Glib::ustring(T::Property::id);
T::Property::office;
Glib::ustring(T::Property::office);
T::Property::cid;
Glib::ustring(T::Property::cid);
T::Property::commentary;
Glib::ustring(T::Property::commentary);
T::Property::date_received;
Glib::ustring(T::Property::date_received);
T::Property::purchases;
Glib::ustring(T::Property::purchases);
T::Property::researches;
Glib::ustring(T::Property::researches);
T::Property::participants;
Glib::ustring(T::Property::participants);
T::Property::departments;
Glib::ustring(T::Property::departments);
T::Property::experts;
Glib::ustring(T::Property::experts);
T::Property::managers;
Glib::ustring(T::Property::managers);
T::Property::lawyers;
Glib::ustring(T::Property::lawyers);
T::Property::collectors;
Glib::ustring(T::Property::collectors);
T::Property::courriers;
Glib::ustring(T::Property::courriers);
T::Property::attachments;
Glib::ustring(T::Property::attachments);
T::Property::payments;
Glib::ustring(T::Property::payments);
T::Property::resolution;
Glib::ustring(T::Property::resolution);
T::Property::date_send_lawyer;
Glib::ustring(T::Property::date_send_lawyer);
};
TEST(CaseModelConformity, Concept) {
ASSERT_TRUE(IsDatabaseModel<CaseModel>) << "Doesn't conform to database model description.";
ASSERT_TRUE(HasModelDbTable<CaseModel>) << "Doesn't have an associated database table.";
ASSERT_TRUE(HasCaseFields<CaseModel>) << "Doesn't have some required fields.";
}
TEST(CaseModelConformity, Properties) {
ASSERT_TRUE(HasNeededProperties<CaseModel>) << "Some required properties are missing.";
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::id), "id");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::office), "office");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::cid), "cid");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::commentary), "commentary");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::date_received), "date_received");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::purchases), "purchases");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::participants), "participants");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::researches), "researches");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::departments), "related_departments");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::experts), "related_experts");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::managers), "related_managers");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::lawyers), "related_lawyers");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::collectors), "related_collectors");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::courriers), "related_courriers");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::attachments), "attachments");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::payments), "payments");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::resolution), "resolution");
EXPECT_EQ(static_cast<Glib::ustring>(CaseModel::Property::date_send_lawyer), "date_send_lawyer");
}
TEST(CaseModelConformity, JsonConversion)
{
ASSERT_TRUE(IsJsonConvertible<CaseModel>);
}
There are too many such object models, each has its own json keys and for each registering the key separately to check for availability - not only will kill a lot of time, but it is also pointless, because all of this can be written into working code. But unfortunately, it is not always possible to identify the change and find out where the key mismatch occurred, as a result of which the backend does not accept json.
Ideally, it would be an option to simply compare the two lists of keys with each other, to identify similarities and differences, but I have very little idea of this, and is it even possible to do it?
Does nlohmann have a method for comparing two lists, not listing each element of this list separately, but passing an object?
I'm using Unit Test using Kotlin and unable to iterate List of Objects in my Test Case, Kindly check my below Coding,
#Test
#WithMockOAuth(siteId = "5698965", subPermissions = [SubPermission.GETD])
fun `get fee zero`() {
val body = """
{
"newMessage": {
"call": true,
"callMessatgeCount": 3,
"discounted": 2,
"NewFees": 4.99,
"Id" : "extra SIM Business"
}
}
""".trimIndent()
this.server.expect(requestTo("${integrationClientProperties.url}/main/0767777777/register/"))
.andRespond(withSuccess(body, MediaType.APPLICATION_JSON_UTF8))
assertThat(service.getValues("0767777777"))
.hasSize(3)
.first()
.hasFieldOrPropertyWithValue("callMessatgeCount", 3)
.hasFieldOrPropertyWithValue("NewFees", BigDecimal.ZERO)
this.server.verify()
}
Above i can able to check hasFieldOrPropertyWithValue for the first() element, As hasSize(3) i need to check all the 3 values which is List of Objects in the same TestCase method.
List of objects as Below
ListValue:[
{
"newMessage": {
"call": true,
"callMessatgeCount": 3,
"discounted": 2,
"NewFees": 4.99,
"Id" : "extra SIM Business"
},
{
"newMessage": {
"call": true,
"callMessatgeCount": 3,
"discounted": 2,
"NewFees": 0,
"Id" : "extra SIM Business"
},
{
"newMessage": {
"call": true,
"callMessatgeCount": 3,
"discounted": 2,
"NewFees": 4.99,
"Id" : "extra SIM Business"
}
]
Note: I tried element(index) to check the list of objects using multiple test cases.
Updated
Library" org.assertj.core.api.Assertions and supports java8
Assuming you are using AssertJ from the method names and that you have a Java-8-supporting version (i.e. 3.5+), you can find the allSatisfy method:
Verifies that all the elements satisfy given requirements expressed as a Consumer.
This is useful to perform a group of assertions on elements.
From the docs, something like the following should work
assertThat(service.getValues("0767777777"))
.hasSize(3)
.allMatch { assertThat(it)
.hasFieldOrPropertyWithValue("callMessatgeCount", 3)
.hasFieldOrPropertyWithValue("NewFees", BigDecimal.ZERO)
}
You could look into Kotlin-specific libraries as well (especially if you need to compile to JVM 6).
I see that have a lot of questions very similar to mine, but I don´t see any solutions that fit with my problem.
I' am trying to create a JSON with boost library with the below structure:
{
"event_date": "2018-06-11T09:35:48.867Z",
"event_log": "2018-06-11 09:35:43,253 - recycler [TRACE]: Running recycler::WITHDRAW",
"cassettes": [
{
"value" : "0",
"currency": "BRL",
"CDMType" : "WFS_CDM_TYPEREJECTCASSETTE",
"lppPhysical" : [
{
"positionName" : "BIN1A",
"count" : "3"
}
]
},
{.....},{.....}
]
}
Below we will have the code that I have now:
boost::property_tree::ptree children, children2, child, child1, child2, child3, child4, child5, cassettes;
child1.put("value", "cash_unit->ulValues");
child2.put("currency", "std::string(cash_unit->cCurrencyID).substr(0, 3)");
child3.put("CDMType", "cash_unit->usType");
child4.put("lppPhysical.positionName", "ph_unit->lpPhysicalPositionName");
child5.put("lppPhysical.count", "cash_unit->ulCount");
cassettes.put("event_date", "2018-06-11T09:35:48.867Z");
cassettes.put("event_log", "2018-06-11 09:35:43,253 - recycler [TRACE]: Running recycler::WITHDRAW");
children.push_back(std::make_pair("", child1));
children.push_back(std::make_pair("", child2));
children.push_back(std::make_pair("", child3));
children2.push_back(std::make_pair("", child4));
children2.push_back(std::make_pair("", child5));
cassettes.add_child("cassettes", children);
write_json("C:\\Temp\\test.json", cassettes);`
Summarizing, I'm having difficulties to put an array of objects inside of an array of objects.
Finally found a solution to my case, it's pretty simple but was hard to find since I am not too familiar with this library.
//LppPhysical insertion
lppPhysicalInfo.put("positionName", ph_unit->lpPhysicalPositionName);
lppPhysicalInfo.put("count", cash_unit->ulCount);
lppPhysical.push_back(std::make_pair("", lppPhysicalInfo));
//Cassettes insertions
cassettesInfo.put("value", cash_unit->ulValues);
cassettesInfo.put("currency", std::string(cash_unit->cCurrencyID).substr(0, 3));
cassettesInfo.put("CDMType", cash_unit->usType);
cassettesInfo.add_child("lppPhysical", lppPhysical.get_child(""));
cassettes.push_back(std::make_pair("", cassettesInfo));
//External information insertion
arquivo.put("event_date", "DateValue");
arquivo.put("event_log", "LogValue");
arquivo.add_child("cassettes", cassettes);
//Json creator
write_json("C:\\Temp\\assassino.json", arquivo);
On the lppPhysical I just make a pair with all its content and on the Cassettes' insertion I just added the lppPhysical as a child of the cassettes and that's it. Now the lppPhysical is an array of object insde the Cassettes which is also an array of objects
I have this body request example:
{
"users": [{
"userId": 123
}, {
"userId": 1234
}]
}
For the previous example I receive one std::list<UsersId>* VUsers that have my userId (in this case '123' and '1234'), create cJSON array, iterate my list and get all userId. (Note: the UsersId is one auxiliar class that I use and receive one int in constructor)
cJSON* cJsonUsers = cJSON_CreateArray();
cJSON_AddItemToObject(root, "VUsers", cJsonUsers);
std::list<UsersId>::const_iterator itUsers = VUsers->begin();
while (itUsers != VUsers->end())
{
cJSON *cJsonVNode = cJSON_CreateObject();
cJSON_AddItemToArray(cJsonUsers, cJsonUser);
cJSON_AddNumberToObject(cJsonUser, "userId", itUsers->userId);
++itVNodes;
}
But know I want to the same but make more simple/easy and need to change the body request to something like this:
{
"users": {
"userId": [123, 1234]
}
}
I'm using this c++ library -> https://github.com/DaveGamble/cJSON but I dont understand how to do to implement the modification that I need.
EDIT 2 (PARSE THE JSON)
cJSON* cJsonUsers = cJSON_GetObjectItem(root, "users");
if (!cJsonUsers) return 0;
if (cJsonUsers->type != cJSON_Array) return 0;
std::list<VUserId>* users = new std::list<VUserId>();
cJSON* cJsonVUser;
cJSON_ArrayForEach(cJsonVUser, cJsonUsers)
{
cJSON* cJsonVUserId = cJSON_GetObjectItem(cJsonVUser, "userId");
if (!cJsonVUserId) continue;
int user_id = cJsonVUserId->valueint;
VUserId userId(user_id);
users->push_back(userId);
}
Something like this could work, that is, create the object and array outside of the loop, and insert the numbers inside the loop:
cJSON* cJsonUsers = cJSON_CreateObject();
cJSON_AddItemToObject(root, "users", cJsonUsers);
cJSON* cJsonUserId = cJSON_CreateArray();
cJSON_AddItemToObject(cJsonUsers, "userId", cJsonUserId);
std::list<UsersId>::const_iterator itUsers = VUsers->begin();
while (itUsers != VUsers->end())
{
cJSON_AddItemToArray(cJsonUserId, cJSON_CreateNumber(itUsers->userId));
++itVNodes;
}
Note that there are languages out there that are more convenient to manipulate JSON if you have the flexibility (disclaimer: I was involved in the design of some of these). Of course there are always use cases when you have to use C++ and in which a library makes a lot of sense.
With languages such as C++ or Java, there is an impedance mismatch between objects in the classical sense, and data formats like XML or JSON. For example, with the standardized, declarative and functional XQuery 3.1 this does not need much code to transform the first document into the second:
let $original-document := json-doc("users.json")
return map {
"users" : map {
"userId" : array { $original-document?users?*?userId }
}
}
I have some documents saved in a collection (called urls) that look like this:
{
payload:{
url_google.com:{
url:'google.com',
text:'search'
}
}
},
{
payload:{
url_t.co:{
url:'t.co',
text:'url shortener'
}
}
},
{
payload:{
url_facebook.com:{
url:'facebook.com',
text:'social network'
}
}
}
Using the mongo CLI, is it possible to look for subdocuments of payload that match /^url_/? And, if that's possible, would it also be possible to query on the match's subdocuments (for example, make sure text exists)?
I was thinking something like this:
db.urls.find({"payload":{"$regex":/^url_/}}).count();
But that's returning 0 results.
Any help or suggestions would be great.
Thanks,
Matt
It's not possible to query against document keys in this way. You can search for exact matches using $exists, but you cannot find key names that match a pattern.
I assume (perhaps incorrectly) that you're trying to find documents which have a URL sub-document, and that not all documents will have this? Why not push that type information down a level, something like:
{
payload: {
type: "url",
url: "Facebook.com",
...
}
}
Then you could query like:
db.foo.find({"payload.type": "url", ...})
I would also be remiss if I did not note that you shouldn't use dots (.) is key names in MongoDB. In some cases it's possible to create documents like this, but it will cause great confusions as you attempt to query into embedded documents (where Mongo uses dot as a "path separator" so to speak).
You can do it but you need to use aggregation: Aggregation is pipeline where each stage is applied to each document. You have a wide range of stages to perform various tasks.
I wrote an aggregate pipeline for this specific problem. If you don't need the count but the documents itself you might want to have a look at the $replaceRoot stage.
EDIT: This works only from Mongo v3.4.4 onwards (thanks for the hint #hwase0ng)
db.getCollection('urls').aggregate([
{
// creating a nested array with keys and values
// of the payload subdocument.
// all other fields of the original document
// are removed and only the filed arrayofkeyvalue persists
"$project": {
"arrayofkeyvalue": {
"$objectToArray": "$$ROOT.payload"
}
}
},
{
"$project": {
// extract only the keys of the array
"urlKeys": "$arrayofkeyvalue.k"
}
},
{
// merge all documents
"$group": {
// _id is mandatory and can be set
// in our case to any value
"_id": 1,
// create one big (unfortunately double
// nested) array with the keys
"urls": {
"$push": "$urlKeys"
}
}
},
{
// "explode" the array and create
// one document for each entry
"$unwind": "$urls"
},
{
// "explode" again as the arry
// is nested twice ...
"$unwind": "$urls"
},
{
// now "query" the documents
// with your regex
"$match": {
"urls": {
"$regex": /url_/
}
}
},
{
// finally count the number of
// matched documents
"$count": "count"
}
])