Creating a json in Play/Scala with same keys but different values - scala

Here's what I want to achieve:
{ "user-list" : {
"user" : [
"username" : "foo"
},
{
"username" : "bar"
}
]
}
}
Im using play-framework and scala.
Thanks!

As previous commenters already pointed out, it is not obvious how to help you, given that your json code is invalid (try JSONLint) and that we don't know where it comes from (string? (case) classes from a database? literals?) and what you want to do with it.
Valid json code close to yours would be:
{
"user-list": {
"user": [
{ "username": "foo" },
{ "username": "bar" }
]
}
}
Depending on how much additional information your structure contains, the following might be sufficient (V1):
{
"user-list": [
{ "username": "foo" },
{ "username": "bar" }
]
}
Or even (V2):
{ "user-list": ["foo", "bar"] }
Following the Play documentation, you should be able to generate V1 with:
val jsonObject = Json.toJson(
Map(
"user-list" -> Seq(
toJson(Map("username" -> toJson("foo"))),
toJson(Map("username" -> toJson("bar")))
)
)
)
and V2 with:
val jsonObject = Json.toJson(
Map(
"user-list" -> Seq(toJson("foo"), toJson("bar"))
)
)

Related

graphene-mongo and nested json data

i have the follow two documents in mongo:
> db.user.find();
{ "_id" : ObjectId("623d12f5ee5204c41f028944"), "uid" : "you", "uid_number" : 5678, "eppns" : [ "you#x.com", "y.com" ], "props" : { "one" : 1, "two" : 2 } }
{ "_id" : ObjectId("623d1310ee5204c41f028945"), "uid" : "me", "uid_number" : 123, "eppns" : [ "me#x.com", "me#y.com" ], "props" : { "one" : 3, "two" : 3 } }
defined with
from mongoengine import Document
from graphene_mongo import MongoengineObjectType
from mongoengine.fields import (
FloatField,
IntField,
DictField,
StringField,
EmailField,
ListField,
URLField,
ObjectIdField,
)
from graphene import ObjectType, Schema, List, Field
from graphene.relay import Node
class User(Document):
meta = { 'collection': 'user' }
ID = ObjectIdField()
uid = StringField(required=True)
uid_number = IntField(required=True)
eppns = ListField( EmailField() )
props = DictField()
class UserType(MongoengineObjectType):
class Meta:
model = User
class Query(ObjectType):
node = Node.Field()
users = List(UserType)
def resolve_users(self, info, **kwargs):
return User.objects.all()
yet, when i query as such:
{ users { id eppns uid uidNumber props } }
i get the following:
{
"data": {
"users": [
{
"id": "623d12f5ee5204c41f028944",
"eppns": [
"you#x.com",
"you#y.com"
],
"uid": "you",
"uidNumber": 5678,
"props": "{\"one\": 1.0, \"two\": 2.0}"
},
{
"id": "623d1310ee5204c41f028945",
"eppns": [
"me#x.com",
"me#y.com"
],
"uid": "me",
"uidNumber": 123,
"props": "{\"one\": 3.0, \"two\": 3.0}"
}
]
}
}
ie, it does not render props as json, but as a string. how can i get props to render/resolve as a dict? i would prefer not to define props as another Document and $ref it.
getting the same problem and I found a possible solution with graphene_django and it solved my problem.
You just need to override your props field with GenericScalar in your UserType:
from graphene.types.generic import GenericScalar # solution
class UserType(MongoengineObjectType):
props = GenericScalar()
class Meta:
model = User

Entity Framework/Linq group related data

I understand GroupBy and Include more or less, but can I group together the records that are included?
I have this working in my controller:
public async Task<IActionResult> Index()
{
return View(await _context.Organizations.Include(x => x.Members).ToListAsync());
}
Which gives me my Organizations and their Members... but I want the members grouped in to their teams. I thought something like:
public async Task<IActionResult> Index()
{
return View(await _context.Organizations.Include(
x => x.Members.GroupBy(m => m.Team)).ToListAsync());
}
But that is incorrect.
I'd like the returned data to be something around (but not necessarily exactly):
[
{
"ID" : "some-guid-string"
"Name" : "MyOrganization",
"Members" : {
"Team1" : [
"MemberName" : "John",
"MemberName" : "Jess",
"MemberName" : "Joe",
],
"Team2" : [
"MemberName" : "Jake",
"MemberName" : "Jeff"
]
}
}
]
I don't think you need to explicitly include fields which are coded in your query. But If I'm wrong, then you just need to replace _context.Organizations with _context.Organizations.Include(o => o.Members).Include(o => o.Members.Select(m => m.Team)) and the reset is the same.
To get a JSON output like this:
[
{
"Id": "some-guid-string",
"Name": "MyOrganization",
"Members":
{
"Team1":
[
"John",
"Jess",
"Joe"
],
"Team2":
[
"Jake",
"Jeff"
]
}
}
]
Could be done with:
_context.Organizations.Select(o => new
{
Id = o.Id,
Name = o.Name,
Members =
o.Members.GroupBy(m => m.Team)
.ToDictionary(kvp => kvp.Key.Name, kvp => kvp.Select(p => p.Name))
});

Update Object at Specific Array Index in MongoDB

I have a collection of the form
{ id : 1,
data: [ [ { name : "alice" }, { name : "bob" } ],
[ { name : "dan" }, { name : "rob" } ] ] }
and the structure of the array has meaning. How would I update the first element ([0][0]) and set name = "alex". I've seen many questions addressing how to update array elements that match a query but not specific elements. To be clear, after the update, the record should look like this:
{ id : 1,
data: [ [ { name : "alex" }, { name : "bob" } ],
[ { name : "dan" }, { name : "rob" } ] ] }
Assuming, you have created the structure with some purpose, which ideally becomes tougher to query, you could update it by specifying the index explicitly:
db.collection.update({"id":1},{$set:{"data.0.0.name":"alex"}})
If we don't have a fixed position and is known at runtime or Dynamic
then this approach works perfectly
var setObject = {};
setObject["board."+ x +"."+ y] = player;
gamesColl.update({_id: realId},{
$set:setObject
}, function(err,doc){
console.log(err,doc);
});
you can go further!!
if you want to paste indexes as a variable use string template like this
db.collection.update({"id":1},{$set:{[`data.${index}.${index}.name`]:"alex"}})

How to update sub document whose parent key has space in?

I have a document like below:
{
"_id" : ObjectId("54b60ee28115386561cda04b"),
"a b" : "{c:d}",
}
I need to update 'a b'.c to value 'e'. Tried query below
db.test.update({"_id" : ObjectId("54b60ee28115386561cda04b")}, {$set:{'a b.c':'e'}});
but get error:
LEFT_SUBFIELD only supports Object: a b not: 2
Any advice, please?
There is nothing wrong with having a space in a key name ( except it looks bad and not a good practice ). So you can modify a correctly formed document with no problem.
{
"_id" : ObjectId("54b60ee28115386561cda04b"),
"a b" : { "c": "d" }
}
And update:
db.test.update(
{ "_id": ObjectId("54b60ee28115386561cda04b") },
{ "$set": { "a b.c": "e" } }
);
But your problem here is that the content of "a b" is a string. So there is no "c" sub-property to access.
{
"_id" : ObjectId("54b60ee28115386561cda04b"),
"a b" : "{c:d}",
}
Correct the document to contain a nested object:
db.test.update(
{ "_id": ObjectId("54b60ee28115386561cda04b") },
{ "$set": { "a b": { "c": "e" } } }
);
Future updates will work properly then

Mongodb MapReduce for grouping up to n per category using Mongoid

I have a weird problem with MongoDB (2.0.2) map reduce.
So, the story goes like this:
I have Ad model (look for model source extract below) and I need to group up to n ads per category in order to have a nice ordered listing I can later use to do more interesting things.
# encoding: utf-8
class Ad
include Mongoid::Document
cache
include Mongoid::Timestamps
field :title
field :slug, :unique => true
def self.aggregate_latest_active_per_category
map = "function () {
emit( this.category, { id: this._id });
}"
reduce = "function ( key, value ) {
return { ads:v };
}"
self.collection.map_reduce(map, reduce, { :out => "categories"} )
end
All fun and games up until now.
What I expect is to get a result in a form which resembles (mongo shell for db.categories.findOne() ):
{
"_id" : "category_name",
"value" : {
"ads" : [
{
"id" : ObjectId("4f2970e9e815f825a30014ab")
},
{
"id" : ObjectId("4f2970e9e815f825a30014b0")
},
{
"id" : ObjectId("4f2970e9e815f825a30014b6")
},
{
"id" : ObjectId("4f2970e9e815f825a30014b8")
},
{
"id" : ObjectId("4f2970e9e815f825a30014bd")
},
{
"id" : ObjectId("4f2970e9e815f825a30014c1")
},
{
"id" : ObjectId("4f2970e9e815f825a30014ca")
},
// ... and it goes on and on
]
}
}
Actually, it would be even better if I could get value to contain only array but MongoDB complains about not supporting that yet, but, with later use of finalize function, that is not a big problem I want to ask about.
Now, back to problem. What actually happens when I do map reduce is that it spits out something like :
{
"_id" : "category_name",
"value" : {
"ads" : [
{
"ads" : [
{
"ads" : [
{
"ads" : [
{
"ads" : [
{
"id" : ObjectId("4f2970d8e815f825a3000011")
},
{
"id" : ObjectId("4f2970d8e815f825a3000017")
},
{
"id" : ObjectId("4f2970d8e815f825a3000019")
},
{
"id" : ObjectId("4f2970d8e815f825a3000022")
},
// ... on and on and on
... and while I could probably work out a way to use this it just doesn't look like something I should get.
So, my questions (finally) are:
Am I doing something wrong and what is it?
I there something wrong with MongoDB map reduce (I mean besides all the usual things when compared to hadoop)?
Yes, you're doing it wrong. Inputs and outputs of map and reduce should be uniform. Because they are meant to be executed in parallel, and reduce might be run over partially reduced results. Try these functions:
var map = function() {
emit(this.category, {ads: [this._id]});
};
var reduce = function(key, values) {
var result = {ads: []};
values.forEach(function(v) {
v.ads.forEach(function(a) {
result.ads.push(a)
});
});
return result;
}
This should produce documents like:
{_id: category, value: {ads: [ObjectId("4f2970d8e815f825a3000011"),
ObjectId("4f2970d8e815f825a3000019"),
...]}}