Swagger (using flask-restx/plus) optional list/nested JSON - flask-restplus

I need the API to accept:
{
'field1' : 10,
'children' : [ 'c1', 'c2' ]
}
and also
{
'field1' : 10,
}
i.e., when there are no children the field can be skipped.
I tried defining the model:
'field1' : fields.Integer(example=42),
'children' : fields.Nested(child_model, as_list=True, allow_null=True, required=False)
and also as:
'field1' : fields.Integer(example=42),
'children' : fields.List(fields.Nested(child_model, as_list=True, allow_null=True), required=False)
and pretty much all combinations of as_list, allow_null, 'skip_noneanddefault` (None, [], etc)
I expected required=False to work for List and/or Nested the same way it works other types.
If the server does not include children in the JSON, marshaling always adds some value .. however, when the client returns an identical JSON to the server marshaling complains.
How can I achieve optional list/nested JSON?

Related

Query for a list contained in another list in mongodb

I'm fairly new to mongo and while I can manage to do most basic operations with the $in, $or, $all, ect I can't make what I want to work.
I'll basically put a simple form of my problem. Part of my documents are list of number, eg :
{_id:1,list:[1,4,3,2]}
{_id:2,list:[1]}
{_id:3,list:[1,3,4,6]}
I want a query that given a list(lets call it L), would return me every document where their entire list is in L
for example with the given list L = [1,2,3,4,5] I want document with _id 1 and 2 to be returned. 3 musn't be returned since 6 isn't in L.
"$in" doesn't work because it would also return _id 3 and "$all" doesn't work either because it would only return _id 1.
I then thought of "$where" but I can't seem to find how to bound an external variable to the js code. What I call by that is that for example :
var L = [1,2,3,4,5];
db.collections('myCollection').find({$where:function(l){
// return something with the list "l" there
}.bind(null,list)})
I tried to bind list to the function as showed up there but to no avail ...
I'd glady appreciate any hint concerning this issue, thanks.
There's a related question Check if every element in array matches condition with an answer with a nice approach for this scenario. It refers to an array of embedded documents but can be adapted for your scenario like this:
db.list.find({
"list" : { $not : { $elemMatch : { $nin : [1,2,3,4,5] } } },
"list.0" : { $exists: true }
})
ie. the list must not have any element that is not in [1,2,3,4,5] and the list must exist with at least 1 element (assuming that's also a requirement).
You could try using the aggregation framework for this where you can make use of the set operators to achieve this, in particular you would need the $setIsSubset operator which returns true if all elements of the first set appear in the second set, including when the first set equals the second set; i.e. not a strict subset.
For example:
var L = [1,2,3,4,5];
db.collections('myCollection').aggregate([
{
"$project": {
"list": 1,
"isSubsetofL": {
"$setIsSubset": [ "$list", L ]
}
}
},
{
"$match": {
"isSubsetofL": true
}
}
])
Result:
/* 0 */
{
"result" : [
{
"_id" : 1,
"list" : [
1,
4,
3,
2
],
"isSubsetofL" : true
},
{
"_id" : 2,
"list" : [
1
],
"isSubsetofL" : true
}
],
"ok" : 1
}

How to query parent based on subdocument's _id?

consider the following records:
user record
{
"_id" : ObjectId("5234ccb7687ea597eabee677"),
"class" : [
{ "_id" : ObjectId("5234ccb7687ea597eabee671", "num" : 10, "color" : "blue" },
{ "_id" : ObjectId("5234ccb7687ea597eabee672", "num" : 100, "color" : "blue" }
]
}
this user has two class sub records, now I need a query that finds all users that have class property where "class._id" has a value of at least one users "class._id"
here is a more detail example:
suppose there is four user:
A:{_id:432645624232345,class:[{_id:123,name:'foo'}]}
B:{_id:432645624232555,class:[{_id:555,name:'foo'},{_id:123,name:'foo'}]}
C:{_id:432645344232345,class:[{_id:555,name:'foo'},{_id:111,name:'www'}]}
D:{_id:432644444232345,class:[{_id:222,name:'sss'},{_id:555,name:'www'},{_id:123,name:'foo'}]}
now if B login , I need to query all the user whose class subdocument contains at least one document which's _id==555 or _id==123 (555 and 123 come from B user), in this case the query result should be:
A:{_id:432645624232345,class:[{_id:123,name:'foo'}]} // match _id=123
B:{_id:432645624232555,class:[{_id:555,name:'foo'},{_id:123,name:'foo'}]} //match _id=123 and _id=555
C:{_id:432645344232345,class:[{_id:555,name:'foo'},{_id:111,name:'www'}]} //match _id=555
D:{_id:432644444232345,class:[{_id:222,name:'sss'},{_id:555,name:'www'},{_id:123,name:'foo'}]} ///match _id=123 and _id=555
which is all the user.
so far i get this:
{"class._id" : { $in : ["5234ccb7687ea597eabee671", "5234ccb7687ea597eabee672"] } }
but when different user login the class._id query condition is different. So is there any operator to do this
{"class._id" : { $in : req.user.class } }
hope I made myself clear.
In order to achieve what you want, first you must isolate the class _ids in an array, and then use it in the query argument.
var classIds = [];
var i = 0;
while (i < req.user.class.length) {
classIds.push(req.user.class[i]._id);
i++;
}
After that you can use classIds array in the query:
{"class._id" : { $in : classIds } }
The following query condition would give you all the users that have at least one class with id equal to any of the elements in the given array:
{"class._id" : { $in : ["5234ccb7687ea597eabee671", "5234ccb7687ea597eabee672"] } }
In the array for the $in clause you may provide any id's you needed , comma separated.
In addition, if you needed such, the below query condition should check for existence of nested document within "class" property that has a property "_id" :
{ "class._id" : { $exists : true } }
Both conditions should work no matter if "class._id" is a single-valued property or an array (mongo supports that).

Filter subdocument and trigger

i have collection of objects inside an invitation, having hard time to filter particular object and trigger it's boolean field.
Document:
"Invitation" : [
{
"__v" : 0,
"userID" : ObjectId("54afaabd88694dc019d3b628"),//ObjectId of personA
"__t" : "USER",
"_id" : ObjectId("54b5022b583973580c706784"),
"Accepted" : false
},
{
"__v" : 0,
"userID" : ObjectId("54af6ce091324fd00f97a15f"),//ObjectId of personB
"__t" : "USER",
"_id" : ObjectId("54bde39cdd55dd9016271f14"),
"Accepted" : false
}
]
here i have only two objects inside Invitation array,it can be more than two.
Let's say personA and personB send me Invitation, so two different invitation objects are inserted into database having different fields, with objectId of both persons(userID in above document), now if i accept only invitation of personA, it should trigger accepted field of personA object only, here is what i tried so far, but not working as per expectation.
Controller:
User.find({_id: req.user._id},'Invitation',function(err,docs) {
if (err) {
console.log(err);
}
var results = [];
async.each(docs,function(doc,callback) {
async.each(doc.Invitation,function(invite,callback) {
User.findOneAndUpdate(
{'_id': doc._id, 'Invitation._id': invite._id},
{'$set': {'Invitation.$.Accepted': !invite.Accepted}},
function(err,doc) {
results.push(doc);
callback(err);
}
);
},callback);
},function(err) {
if (err)
console.log(err);
console.log('end'+results);
});
});
finally i am looking for a query which can be used to filter a single element or object, like if i accept invitation of personA then Accepted field of personA object should be set to true.
i would be really helpful if some logic is provided.
Thank you
Not a very clear question. But it seems all you really need to do here is just match the only sub-document you want to update in the first place:
User.find(
{
"_id": "req.user._id",
"Invitation._id": personA.id
},
{ "Invitation.$": 1 },
function(err,docs) {
// and continue
}
);
This is the form of the positional $ operator in a "projection" context. Where only the "singular" matched element is returned.
Once you have a "singular" result, then all the other code works as designed.
I should know after all because I wrote it for you. Not that you are paying any decent respect to that.
Update on Aggregate in Mongodb
Toggle boolean value of subdocuments
Or personA.userID or whatever makes it work.
Just use the unique identifier for the "user" where you expect that to match the query conditions.
You can do this:
db.user.update({"invitation.userID": 1}, {"$set" : {"invitation.$.Accepted" : true}});
Replacing the value 1 with the user ID you want to update.
The code is in the syntax of MongoShell, simply convert to driver syntax you are using
The operator used was the $. According to the documentation: The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array. To project, or return, an array element from a read operation, see the $ projection operator.
For more details see: http://docs.mongodb.org/manual/reference/operator/update/positional/

Elasticsearch Analyze API Oddity

My question is fairly simple. Say that I have a type mapping in an index that looks like this:
"mappings" : {
"post" : {
"analyzer" : "my_custom_analyzer",
"properties" : {
"body" : {
"type" : "string",
"store" : true
}
}
}
}
Note that I specified my_custom_analyzer as the analyzer for the type. When I search the body field without specifying an analyzer in the query, I expect my_custom_analyzer to be used. However, when I use the Analyze API to query the field:
curl http://localhost:9200/myindex/_analyze?field=post.body&text=test
It returns standard analysis results for string. When I specify the analyzer it works:
curl http://localhost:9200/myindex/_analyze?analyzer=my_custom_analyzer&text=test
My question is: why doesn't the Analyze API use the default type analyzer when I specify a field?
Analyzer is per string field.
You cant apply it over an object or nested object and hope all the fields under that object field will inherit that analyzer.
The right approach is as follows -
"mappings" : {
"post" : {
"properties" : {
"body" : {
"type" : "string",
"analyzer" : "my_custom_analyzer",
"store" : true
}
}
}
}
The reason the analyzer worked for analyzer API is because you have declared analyzer for that index.
If you want to define analyzer for all the string fields under a particular object ,you need to mention that in the type template. You can get more information about that here - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html#_dynamic_templates

Backbone fetch parent model with nested collection

My aplication has this structure:
Project (model)
-> tracks (collection)
-> track (model)
-> clips (collection)
clip (model)
I need to fetch only parent project model. It will cause change of all data structure. I get JSON
{ "_id" : "123",
"name" : "name",
"tracks" : [ { "clips" : [ { "audioName" : "audio name",
"audioPath" : "audio/path.wav",
"duration" : 123,
"id" : "track0-1"
} ],
"mute" : false,
"name" : "track0",
"selected" : false,
"volume" : 100
},
{ "clips" : [ ],
"mute" : false,
"name" : "track1",
"selected" : false,
"volume" : 100
}
]
}
I have parse method:
parse: function (data) {
this.get('tracks').reset(data.tracks);
delete data.tracks;
return data;
}
I am not able to parse clips. In model track, attribute clips has behavior like javascript array instead of backbone model.
How can I parse clips?
parse is only used to parse responses from the server. So you won't be able to use it to create your clips collection.
So you may want to change the way you do that (maybe have a look at Backbone-relational, I think it deals with this kind of stuff). Here's a possible solution (to be put in your model):
initialize: function() {
this.listenTo(this, 'change:clips', this.onChangeClips);
// the rest of your stuff
},
onChangeClips: function() {
var clips = this.get('clips');
if(Object.prototype.toString.call(clips) === '[object Array]')
this.set('clips', new Clips(clips), {silent: true});
}
Source to test if array: Check if object is array?
Note: this will remove any reference to an existing collection (which you seem to have), so you may want to keep a reference to your collection in your model (like in a _clips attribute) to reset it with the new clips array.

Resources