graphene-mongo and nested json data - mongodb

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

Related

Django Rest Framework and MongoDB - listField does not works It returns None when object is embedded

I'm using MongoDB the connection is provided by Djongo, over is being used DRF to manage all request to mi API.
My data (profile) is structured like this
{
"name" : "profile name",
"description" : "this is a description",
"params" : "X1, X2,X3, etc",
"config" : "CONFIG OF DEVICE",
"user" : {
"name" : "user name",
"middle_name" : "test middle name",
"last_name" : "test last name",
"email" : "test#test.com",
"institute" : {
"name" : "MIT",
"place" : {
"coordinates" : [ 30.0, 101.0, 0.0 ],
"type" : "Point"
},
"country" : "US"
}
},
"place" : {
"coordinates" : [ 90.0, 901.0, 10.0 ],
"type" : "Point"
},
"devices" : [
{
"name" : "DEVICE 1",
"verification_code" : "",
"verificated" : 0,
"configuration" : "kjk",
"places" : [
{
"coordinates" : [ 30.0, 101.0, 0.0 ],
"type" : "Point"
},
{
"coordinates" : [ 31.0, 102.0, 1.0 ],
"type" : "Point"
}
]
}
]
}
I know, the coordinates are wrong, but is just for test.
Well I send that object to my view and then to the ProfileSerializer, this get the responsible to check the embedded objects (each one have your own serializer). After checking data, the info is saved without problem as you can see in next picture:
But the problem is when I try to. retrieve all profiles. Just the coordinates are null, Other embedded objects are retrieved in good way, only the Place Object is malformed. Next, I'll show you the response:
[
{
"id": 22,
"name": "profile name",
"description": "this is a description",
"params": "X1, X2,X3, etc",
"config": "CONFIG OF DEVICE",
"user": {
"name": "user name",
"middle_name": "test middle name",
"last_name": "test last name",
"email": "test#test.com",
"institute": {
"name": "MIT",
"place": {
"coordinates": **null**,
"type": "Point"
},
"country": "US",
"created_at": "2019-03-21T20:43:33.928000Z"
},
"created_at": "2019-03-21T20:43:33.959000Z"
},
"place": {
"coordinates": **null**,
"type": "Point"
},
"devices": [
{
"name": "DEVICE 1",
"verificated": 0,
"configuration": "kjk",
"places": [
{
"coordinates": **null**,
"type": "Point"
},
{
"coordinates": **null**,
"type": "Point"
}
],
"created_at": "2019-03-21T20:43:33.898000Z"
}
],
"created_at": "2019-03-21T20:43:33.976000Z"
}
]
For this questions only I'll describe/show the serializer of one object, but if you need some info I'll get you as soon as possible.
Models
class Place(models.Model):
coordinates = models.ListField(blank=True, null=True, default=[0.0, 0.0, 0.0])
type = models.CharField(max_length=10, default="Point")
objects = models.DjongoManager()
class Profile(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(default="Without Description")
params = models.TextField(default="No params")
config = models.CharField(max_length=200)
user = models.EmbeddedModelField(
model_container=User
)
place = models.EmbeddedModelField(
model_container=Place
)
devices = models.ArrayModelField(
model_container=Device
)
created_at = models.DateTimeField(auto_now_add=True)
objects = models.DjongoManager()
Serializers
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer(
child=serializers.FloatField(),
)
class Meta:
model = Place
fields = ('id', 'coordinates', 'type')
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer( )
place = PlaceSerializer()
devices = DeviceSerializer( many=True)
class Meta:
model = Profile
fields = ('id', 'name', 'description', 'params', 'config',
'user', 'place', 'devices', 'created_at')
depth=8
def create(self, validated_data):
# get principal fields
user_data = validated_data.pop('user')
**place_data = validated_data.pop('place')**
devices_data = validated_data.pop('devices')
# get nested fields
# devices nested fields
devices = []
for device in devices_data:
places = []
places_data = device.pop('places')
for place in places_data:
places.append( **Place(coordinates=place['coordinates'], type=place['type'])** )
device['places'] = places
devices.append( Device.objects.create(**device) )
validated_data['devices'] = devices
# user nested fields
institute_data = user_data.pop('institute')
place = institute_data.pop('place')
institute_data['place'] = Place(coordinates=place['coordinates'], type=place['type'])
user_data['institute'] = Institute.objects.create(**institute_data)
validated_data['user'] = User.objects.create(**user_data)
profile = Profile.objects.create(**validated_data)
return profile
I've defined PlaceSerializer on many ways but all of them gets the same result, Below describe this ways
CASE 1
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer(
child=serializers.FloatField(),
)
CASE 2
class CoordinatesSerializer(serializers.ListSerializer):
child=serializers.FloatField()
class PlaceSerializer(serializers.ModelSerializer):
coordinates = CoordinatesSerializer()
CASE 3
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListField(
child=serializers.FloatField()
)
CASE 4
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListField()
CASE 5
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer()
#gives error for child is not present
I had changed the types, CharField, IntegerField, FloatField, etc with same results.
Another tests that I've done are append to serializer the methods create, update, to_representation, to_internal_value, all of this for to manage in a better way the info that will saved o retrieved but any works. Another curiosity, if I add a simple Listfield like [10,90,1], is saved and retrieved without problem in contrast when this ListField is inside Place Objects
Please if you know how to solve this I'll glad to you.

Adding elements to JSON array using circe and scala

I have a JSON string as the following:
{
"cars": {
"Nissan": [
{"model":"Sentra", "doors":4},
{"model":"Maxima", "doors":4},
{"model":"Skyline", "doors":2}
],
"Ford": [
{"model":"Taurus", "doors":4},
{"model":"Escort", "doors":4}
]
}
}
I would like to add a new cars brand (in addition to Nissan and Ford), using circe at scala.
How could I do it?
Thank you in advance.
You can modify JSON using cursors. One of the possible solutions:
import io.circe._, io.circe.parser._
val cars: String = """
{
"cars": {
"Nissan": [
{"model":"Sentra", "doors":4},
{"model":"Maxima", "doors":4},
{"model":"Skyline", "doors":2}
],
"Ford": [
{"model":"Taurus", "doors":4},
{"model":"Escort", "doors":4}
]
}
}"""
val carsJson = parse(cars).getOrElse(Json.Null)
val teslaJson: Json = parse("""
{
"Tesla": [
{"model":"Model X", "doors":5}
]
}""").getOrElse(Json.Null)
val carsCursor = carsJson.hcursor
val newJson = carsCursor.downField("cars").withFocus(_.deepMerge(teslaJson)).top
Here we just go down to cars field, "focus" on it and pass the function for modifying JSON values. Here deepMerge is used.
newJson will be look as follows:
Some({
"cars" : {
"Tesla" : [
{
"model" : "Model X",
"doors" : 5
}
],
"Nissan" : [
{
"model" : "Sentra",
"doors" : 4
},
{
"model" : "Maxima",
"doors" : 4
},
{
"model" : "Skyline",
"doors" : 2
}
],
"Ford" : [
{
"model" : "Taurus",
"doors" : 4
},
{
"model" : "Escort",
"doors" : 4
}
]
}
})

access id of a nested document in mongoose

I want to write a put method in express for a nested document in mongoose.
I cannot access the id for the nested document.
{ "_id" : ObjectId("5b8d1ecbb745685c31ad8603"),
"name" : "abc",
"email" : "abc#gmail.com",
"projectDetails" : [
{
"technologies" : [
"abc",
"abc"
],
"_id" : ObjectId("5b8d1ecbb745685c31ad8604"),
"projectName" : "abc",
"projectDescription" : "abc",
"manager" : "abc",
"mentor" : "abc"
}
],
"__v" : 0
}
I am trying to access the id ("5b8d1ecbb745685c31ad8604") so that I can update the projectName.
I cannot think of how to write a put method for the same. Please help! Thanks in advance!!
You can use model.findOne() and then save() th update the document instead of model.findOneAndUpdate().
var projectId = "5b8d1ecbb745685c31ad8604";
var newProjectName = "def";
model.findOne({'projectDetails._id': projectId}, (err, data) => {
if (data) {
data.projectDetails.forEach((project) => {
if (project._id == projectId) {
project.projectName = newProjectName;
}
});
data.save();
} else {
// throw error message
}
})
app.put('/api/project/:id',(request,response)=>{
const projectId = request.params.id;
const projectName = "test";
db.users.update({"projectDetails._id":projectId},{$set:{"projectDetails.$.projectName":projectName}},function(err,data){
if(data){
}else{
}
})})
Instead of forEach try above query

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))
});

Find the documents in mongoose whose array fields exactly match

I'm using Mongoose and have a schema like this:
var chat = new mongoose.Schema({
chatId : String,
members : [{
id : String,
name : String
}]
});
Suppose I have two chat document like this
{
chatId : 'Edcjjb',
members : [
{
id : 'a1',
name : 'aaa'
},
{
id : 'b1',
name : 'bbb'
}
]
}
{
chatId : 'Fxcjjb',
members : [
{
id : 'a1',
name : 'aaa'
},
{
id : 'b1',
name : 'bbb'
},
{
id : 'c1',
name : 'ccc'
}
]
}
I want to find all those documents which have only specfied members Id.
For example, if I specify a1 and b1
then only the first document should be retrieved as the second document contains id c1 as well.
And if I specifiy a1,b1,c1
then only second document should be specified.
Please tell me how to do this in mongoose
You can specify a clause on the array size, like
{ members : { $size : 2 } } in your first example and
{ members : { $size : 3 } } in the second one.
Can that work for you?
EDIT: I should also mention that the other part of the query should be
{ "members.id": { $all: [ "a1" , "b1" ] } }
and, for the second example,
{ "members.id": { $all: [ "a1" , "b1", "c1" ] } }