How do I use groovy jsonbuilder with .each to create an array? - arrays

I would like to create an array with JSON-Builder.
Expected format:
{
"Header": {
"SomeKey" : "SomeValue"
}
"Data": [
{
"SomeKey" : "SomeValue"
},
{
"SomeKey" : "SomeValue"
}
]
}
My Code:
def builder = new groovy.json.JsonBuilder()
def root = builder {
Header {
"Typ" "update"
"Code" "UTF-8"
"TransaktionsNr" item.transactionNumber
"DatumZeit" new Date().format("dd.MM.yyyy HH:mm")
}
customers.each ({ customer->
"Data" {
"Email" customer.code
"Newsletter" customer.newsletterSubscribed
}
})
However whatever I do I only get one element in the Data section. I tried using [] instead of {}, but I still only get one element, what am I doing wrong?

That's duplicate key for JSON structure. There should not be duplicate key in the same hierarchy or they will override each other:
class Customer { String code; boolean newsletterSubscribed }
customers = [
new Customer(code:"11111", newsletterSubscribed:true),
new Customer(code:"22222", newsletterSubscribed:false)
]
def builder = new groovy.json.JsonBuilder()
def root = builder {
Header {
"Typ" "update"
"Code" "UTF-8"
"TransaktionsNr" 987
"DatumZeit" new Date().format("dd.MM.yyyy HH:mm")
}
customers customers.collect { customer ->
["Email":customer.code,
"Newsletter":customer.newsletterSubscribed]
}
}
assert builder.toString() == {"Header":{"Typ":"update","Code":"UTF-8","TransaktionsNr":987,"DatumZeit":"21.12.2012 13:38"},"Data":{"Email":"22222","Newsletter":false},"customers":[{"Email":"11111","Newsletter":true},{"Email":"22222","Newsletter":false}]}

Related

Swiftui User Multiple Selection To Array of Object

I have the following response from API
"features": [
{
"name": "Safety",
"_id": "636a638959d10a2603b8d645",
"values": [
Array of String
]
},
{
"name": "Entertainment",
"_id": "636a64312bbe0cd292a1ffc6",
"values": [
Array of String
]
Which I decode it with :
struct Feature : Codable , Hashable{
var name : String = ""
var values : [Value] = []
}
struct Value : Codable, Hashable{
var value : String = ""
var unit : String = ""
}
And in the view is render it like :
var body: some View {
VStack{
HStack{
Text("Choose Your Features").font(Font.body.bold())
Spacer()
}.padding(.leading, 15)
ScrollView(.vertical, showsIndicators: false){
VStack{
ForEach(Array(features.enumerated()), id: \.offset) { featureIndex, feature in
HStack{
Text(feature.name).font(Font.body.bold())
Spacer()
}.padding(.bottom , 10)
ScrollView(.horizontal, showsIndicators: false){
HStack(spacing : 10){
ForEach(Array(feature.values.enumerated()), id: \.offset) { valueIndex, value in
FeatureCell(isSelected: $isSelected, value: value).onTapGesture{
// here
}
}
}
Divider().padding(10)
}
}.padding(15)
}
}
}
}
The user may select multiple item from each feature values list, Now Im really confused about how to store these selections in an array of features object again, I tried almost every thing like Array, Set and Dictionaries but could not reach any solution.
Update : This is the json object I should send back
{
"features": [
{
"Safety": [
"value1",
"value9",
"value3"
]
},
{
"Entertainment": [
"value7",
"value2",
"value8"
]
}
]
}
Any help or ideas will be much appreciated
You usually want to use a Set to store which items are selected. This set should be a State variable instantiated in the parent view. The onTapGesture closure will add or remove the value to the set. If the FeatureCell needs to know whether the value is selected, simply use the .contains method.
struct FeatureValueSelectionView: View {
// The feature whose values we are displaying
let feature: Feature
// Note: You may have to manually conform Value to the Hashable protocol
#State private var selectedValues = Set<Value>()
var body: some View {
ForEach(feature.values) { value in
FeatureCell(selected: selectedValues.contains(value), value: value)
.onTapGesture { selectedValues.toggle(value) }
}
}
}
For toggling a value in a set, I like to use this simple extension:
extension Set {
public mutating func toggle(_ element: Element) {
if self.contains(element) {
self.subtract([element])
} else {
self.insert(element)
}
}
}

MongoDB : Complex Arrary field

{
"_id" : ObjectId("58d9084841a6168234689aee"),
"ID" : "01",
"data" : {
"Type1" : {
"value" : "ABC",
"timestamp" : "2017-03-20 16:01:01"
},
"Type2" : {
"value" : "ccc",
"timestamp" : "2017-03-20 16:01:01"
}
}
}
I want to get timestamp of each TYPE from mongodb using queryobject using nodejs.
How to get it,Please help.
var queryObject = url.parse(req.url,true).query;
var mdb = db.collection("HISTORY").find({{'timestamp':{"$gte":queryObject.fromdate,"$lt" : queryObject.todate}},{"ID":1});
Here is my node service:
function getHistory(req,res){
try{
var queryObject = url.parse(req.url,true).query;
var index=0, resultset = [];
var db1 = db.collection("HISTORY").find({$and : [{'data.Type1.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}},
{'data.Type2.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}},
{'data.Type3.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}},
{'data.Type4.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}},
{'data.Type5.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}}
]},{"Ino":1,"ID":1,"data":1});
db1.count(function(err, count) {
console.log("count" , count);
db1.each(function(err, doc) {
if(doc!=null){
var valdata=doc.alarms;
var fields = [];
var queryString ="SELECT field1,NAME FROM details c inner join locdetails l on c.loc_id=l.loc_id where no='"+doc.Ino+"' limit 1;";
var dtfield1 = null;
var dtfield2 = null;
connection.query(queryString, function(err,result){
index++;
if(err){
}else{
if(result.length>0)
{
dtfield1 = result[0].field1;
dtfield2 = result[0].NAME;
if(dtfield1!=null){
for (var x in valdata) {
var dt = new Date(valdata[x].timestamp).toISOString().replace(/T/, ' ').replace(/\..+/, '');
var compareDate = new Date(dt);
if(compareDate.getTime()>=fromDate.getTime()&&compareDate.getTime()<=toDate.getTime()){
resultset.push({"Name":dtfield1,"LName":dtfield2,"Ino":doc.Ino,"ID":doc.ID,"data":x,"datav":valdata[x].value,"Timestamp":valdata[x].timestamp});
}
if(index == count){
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.write(JSON.stringify(resultset));
res.end();
}
}} }}
});
} else {
}
});
});
}
catch (err) {
console.log("Exception -- ",err);
}
}
I want data should filter based on timestamp and same can be display in UI and download the displayed data.And also filter should be in UI like current day data and based on time filter also.
If you want search base on both Type1.timestamp and Type2.timestamp, you should use $and. you can change $and with $or if one matching one of them is enough
db.collection("HISTORY").find({
$and : [{'data.Type1.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}},
{'data.Type2.timestamp':{"$gte": new Date(queryObject.fromdate),"$lt" : new Date(queryObject.todate)}}
]
},
{ID:1}, function (err, res){
});
You can use aggregation to meet your requirements.
For your initial list which will only show the latest data values of each object, you can use the following pipeline -
[
{
$project:{
_id:1,
ID:1,
data:{ $objectToArray: "$data" }
}
},
{
$unwind:"$data"
},
{
$sort:{
"data.v.timestamp":-1
}
},
{
$group:{
_id:{
_id:"$_id",
ID:"$ID"
},
data:{
$first:"$data"
}
}
},
{
$addFields:{
data:["$data"]
}
},
{
$addFields:{
data:{ $arrayToObject: "$data" }
}
}
]
The result of the aggregation should give you an array of objects like this -
{
"_id" : ObjectId("5bc469c11f8e482416d6edb3"),
"ID" : "01",
"data" : {
"Type2" : {
"value" : "ccc",
"timestamp" : ISODate("2017-03-22T16:01:01.000+06:00")
}
}
}
As for filtering the collection to get documents with data properties that have timestamp values in the given range, the above pipeline can be modified to acquire it
[
{
$project:{
_id:1,
ID:1,
data:{ $objectToArray: "$data" }
}
},
{
$unwind:"$data"
},
{
$sort:{
"data.v.timestamp":-1
}
},
{
$match:{
"data.v.timestamp":{ $gt: "start date value", $lt: "end date value"}
}
},
{
$group:{
_id:{
_id:"$_id",
ID:"$ID"
},
data:{
$addToSet:"$data"
}
}
},
{
$project:{
_id:"$_id._id",
ID:"$_id.ID",
data:{ $arrayToObject: "$data" }
}
}
]
The result of this aggregation will produce array of objects similar to the one described above. But this time each document's data object will only have properties that match the timestamp condition.
Hope this helps. A final word of advice to you would be to rethink the schema design of the history collection. Because if simplistic date based queries are getting this difficult for you. You can only imagine what the future might hold for you with this design.

Add array values into MongoDB where element is not in array

In MongoDB, this is the simplified structure of my account document:
{
"_id" : ObjectId("5a70a60ca7fbc476caea5e59"),
"templates" : [
{
"name" : "Password Reset",
"content" : "AAAAAAAA"
},
{
"name" : "Welcome Message",
"content" : "BBBBBB"
}
]
}
There's a similar default_templates collection
let accnt = await Account.findOne({ _id: req.account._id }, { templates: 1 });
let defaults = await DefaultTemplate.find({}).lean();
My goal is to find the missing templates under account and grab them from defaults. (a) I need to upsert templates if it doesn't exist in an account and (b) I don't want to update a template if it already exists in an account.
I've tried the following:
if (!accnt.templates || accnt.templates.length < defaults.length) {
const accountTemplates = _.filter(accnt.templates, 'name');
const templateNames = _.map(accountTemplates, 'name');
Account.update({ _id: req.account._id, 'templates.name' : { $nin: templateNames } },
{ '$push': { 'templates': { '$each' : defaults } } }, { 'upsert' : true },
function(err, result) {
Logger.error('error %o', err);
Logger.debug('result %o', result);
}
);
}
This succeeds at the upsert but it will enter all default templates even if there's a matching name in templateNames. I've verified that templateNames array is correct and I've also tried using $addToSet instead of $push, so I must not understand Mongo subdoc queries.
Any ideas on what I'm doing wrong?
Edit: I've gotten this to work by simply removing elements from the defaults array before updating, but I'd still like to know how this could be accomplished with Mongoose.
You can try with bulkWrite operation in mongodb
Account.bulkWrite(
req.body.accountTemplates.map((data) =>
({
updateOne: {
filter: { _id: req.account._id, 'templates.name' : { $ne: data.name } },
update: { $push: { templates: { $each : data } } },
upsert : true
}
})
)
})

$push in MongoDb not working?

my schema looks like this:
var exampleSchema = newSchema({
profile:{
experience :[{
exp : String
}]
}
});
this is the codes to update experience in profile collection:
exampleSchema.statics.experience = function (id,experience, callback){
var update = {
$push: {
'profile.experience': experience
}
}
this.findByIdAndUpdate(id,update,function(err) {
if (err) {
callback(err);
} else {
callback(null);
}
})
I was getting error like The field 'profile.experience' must be an array but is of type String in document {_id: ObjectId('5653f1d852cf7b4c0bfeb54a')}[object Object]
console.log(experience) is equal to
{ exp: 'jlkjlkjlk' }
my collection should look like this:
experience:[
{
exp : "YYYY"
},
{
exp:"xxxx"}
]
Imagine that you have this collection:
/* 1 */
{
"_id" : ObjectId("565425e862760dfe14339ba8"),
"profile" : {
"experience" : [
{
"exp" : "Experto"
}
]
}
}
/* 2 */
{
"_id" : ObjectId("565425f562760dfe14339ba9"),
"profile" : {
"experience" : {
"exp" : "Experto"
}
}
}
/* 3 */
{
"_id" : ObjectId("5654260662760dfe14339baa"),
"profile" : {
"experience" : "Experto"
}
}
If you try (update doc /* 2 */):
db.profile.update(
{ _id: ObjectId("565425f562760dfe14339ba9") },
{ $push: { "profile.experience" : { exp : "Intermediate" } } }
)
You get this error:
The field 'profile.experience' must be an array but is of type Object
in document {_id: ObjectId('565425f562760dfe14339ba9')}
And if you try (update doc /* 3 */):
db.profile.update(
{ _id: ObjectId("5654260662760dfe14339baa") },
{ $push: { "profile.experience" : { exp : "Intermediate" } } }
)
You will get:
The field 'profile.experience' must be an array but is of type String
in document {_id: ObjectId('5654260662760dfe14339baa')}
i changed Schema like this
experience : [{type:String,exp:String}],
my update object looks like this
var update = {
$push: {
'profile.experience': san.exp
}
};
san looks like this :{ exp: 'YYY' }
Inside mongoose collectionlooks like this used RoboMongo
"experience" : [
"experienced in XXX",
"YYY"
],
$push: {
'profile.experience': experience
}
Remove .exp.
First you have to check you declared your field as an array like this(look at field products):
shop = {
'name': "Apple Store",
'description': "",
'direction': "",
'contact': "",
'products':[]
}
Now if you want to add something to the field products using $push
product = {
'name': "Iphone 6",
'description': "Iphone model 6, 64GB",
'price': 700,
'count': 3
}
myquery = { "name" : "Apple Store" }
obj ={"$push":{"products":{"$each": [product]}}}
db.collection.update_one(myquery,obj)
This code is provided for PyMongo framework. To use in MongoDB directly replace update_one by update. Mongo resource
You may use $set instead of $push which might work.
$set: {
'profile.experience': experience
}
are you searching for adding multiple values into single field then use this one.
write this one your model or schema:
arrayremarks:[{remark: String}]
then write in your controller:
module.exports.addingremarks = (req, res) => {
let casenum=JSON.parse(JSON.stringify(req.body.casenum).replace(/"\s+|\s+"/g,'"'))
var rem={remark:"Suman macha"}
Inwart.update( { 'casenum': casenum },{ $push: { arrayremarks:rem} } ,function (err, inwarts) {
if (err)
return console.error(err);
res.send(inwarts);
}
)
}

SwiftyJSON Append new data to existing JSON array

I am working on a way to add new JSON data to my existing JSON array:
var resources: JSON = [
"resources": []
]
override func viewDidLoad() {
super.viewDidLoad()
getApiResourceA() { responseObject, error in
var resourceA: JSON = [
"resourceA": []
]
let resourceAResponseObject = JSON(responseObject!)
resourceA["resourceA"] = resourceAResponseObject
self.resources["resources"] = resourceA
}
getApiResourceB() { responseObject, error in
var resourceB: JSON = [
"resourceB": []
]
let resourceBResponseObject = JSON(responseObject!)
resourceB["resourceB"] = resourceBResponseObject
self.resources["resources"] = resourceB
}
}
The structure I am trying to get is:
{
"resources": {
"resourceA": {
"id": 1
"name": "Name1"
}
"resourceB": {
"id": 2
"name": "Name2"
}
}
}
But in my code there are two different "resources"-array created...
Anyone know how to deal with this?
First it is important to understand that JSON is Struct means it is duplicated every time you pass it or use it.
Another issue, you declared resources as Array and not as Dictionary means you can use resource as key.
Declare extensions:
extension JSON{
mutating func appendIfArray(json:JSON){
if var arr = self.array{
arr.append(json)
self = JSON(arr);
}
}
mutating func appendIfDictionary(key:String,json:JSON){
if var dict = self.dictionary{
dict[key] = json;
self = JSON(dict);
}
}
}
use:
//notice the change [String:AnyObject]
var resources: JSON = [
"resources": [String:AnyObject](),
]
resources["resources"].appendIfDictionary("resourceA", json: JSON(["key1":"value1"]))
resources["resources"].appendIfDictionary("resourceB", json: JSON(["key2":"value2"]))
result:
{
"resources" : {
"resourceB" : {
"key2" : "value2"
},
"resourceA" : {
"key1" : "value1"
}
}
}
#daniel-krom has right, but is a little confusing implement the extension, so, we need only add at the end of the Swift controller (or class) that code that adds the "append" methods, nothing else.
Using the appendIfArray method, I could pass from this
[
{
"id_usuario" : 2
}
]
...to this
[
{
"id_usuario" : 2
},
{
"id_usuario" : 111
},
{
"id_usuario" : 112
},
{
"id_usuario" : 113
}
]
The complete code is below:
do{
try json2!["usuarios"][indice]["fotos"][0]["me_gusta"].appendIfArray(json: JSON( ["id_usuario": 111] ))
try json2!["usuarios"][indice]["fotos"][0]["me_gusta"].appendIfArray(json: JSON( ["id_usuario": 112] ))
try json2!["usuarios"][indice]["fotos"][0]["me_gusta"].appendIfArray(json: JSON( ["id_usuario": 113] ))
}catch {
print("Error")
}
The complete JSON structure can find in
http://jsoneditoronline.org/?id=56988c404dcd3c8b3065a583f9a41bba
I hope this can be useful

Resources