Odata sort by min value from array - request

I have odata query:
/url/odata/ContractCards?
$top=20&
$count=true&
$filter=ContractId%20eq%2013ff820e-1ac7-ea11-a97d-899ae03249bd&
$orderby=LicenseType/Name%20asc&
$select=Id,ContractId,CardNumber,Name&
$expand=
Contract($select=ContractTypeCode,ContractVersionSetId),
ContractCardRightAssignments
($orderby=Right/Name%20asc;
$select=Id,ContractCardId,StartDate,EndDate,IsEstimatedStartDate,
IsEstimatedEndDate,IsInPerpetuity,RightId,Note,RunCount,RunCountNote,
IsRunCountUnlimited,HoldBackLength;
$expand=Right($select=Id,Name,TypeCode),
HoldbackType($select=Id,Name),
HoldbackFromRightGroup($select=Id,Name),
...
)
The result of the query is sorted by LicenseType.Name list of contractCards:
{
value:[
{
ContractCardName:"ContractCard1",
ContractCardRightAssignments:[{RightName:"Right1",StartDate:"2020-01-01"},{RightName:"Right2",StartDate:"2019-01-01"}],
LicenseType:{Name:"A license"}
},
{
ContractCardName:"ContractCard2",
ContractCardRightAssignments:[{RightName:"Right3",StartDate:"2019-01-01"},{RightName:"Right4",StartDate:"2018-01-01"}],
LicenseType:{Name:"B license"}
},
{
ContractCardName:"ContractCard3",
ContractCardRightAssignments:[{RightName:"Right3",StartDate:"2018-01-01"},{RightName:"Right4",StartDate:"2017-01-01"}],
LicenseType:{Name:"C license"}
}
]
}
I want to change sorting, to get the result sorted by min(StartDate) value, so the result should looks like(2017,2018,2019):
{
value:[
{
ContractCardName:"ContractCard3",
Rights:[{RightName:"Right3",StartDate:"2018-01-01"},{RightName:"Right4",StartDate:"2017-01-01"}],
LicenseType:{Name:"C license"}
},
{
ContractCardName:"ContractCard2",
Rights:[{RightName:"Right3",StartDate:"2019-01-01"},{RightName:"Right4",StartDate:"2018-01-01"}],
LicenseType:{Name:"B license"}
},
{
ContractCardName:"ContractCard1",
Rights:[{RightName:"Right1",StartDate:"2020-01-01"},{RightName:"Right2",StartDate:"2019-01-01"}],
LicenseType:{Name:"A license"}
}
]
}
I tried to change the query in part
$orderby=LicenseType/Name%20asc&
to something like
$orderby=ContractCardRightAssignments/StartDate.Min()%20asc
but no luck.
How to change the query to order the reault in a such way?

Related

how to update data in mongodb using angular nodejs express

I want to update the likes' value with 1.
My MongoDB structure is as follows .
{"_id":{"$oid":"5f980a66c4b0d52950bdf907"},
"course_id":"5002",
"lecture_id":"451",
"__v":0,
"created_at":{"$date":"2020-10-27T11:54:14.842Z"},
"message":[
{
"_id":{"$oid":"5f980a84c4b0d52950bdf90a"},
"from":{
"userId":"68819","name":"Developer IIRS",
"avatar":"https://api.adorable.io/avatars/285/811753.png"
},
"content":"ok",
"likes":0,
"parent_id":null,
"created_at":{"$date":"2020-10-27T11:54:44.388Z"}
}
]
}
Here is my code to update value of likes
router.post('/:lectureId/:courseId/:id', function(req, res, next) {
let query = {
lecture_id: req.params.lectureId,
course_id: req.params.courseId
};
let update = { $push: { message: { _id: req.params.id,likes: 1 } } }
var options = {
new: true
}
console.log('Liked', query)
Chat.update(query, update, function(err, result) {
if (err) {
//res.send(err);
console.log('err',err );
return err;
}
res.json(result);
})
});
Its basically adding new document. I am stuck here how can i do this.
"lecture_id": "451",
"course_id": "5002"
},
{
$inc: {
"message.$[elem].likes": 1
}
},
{
new: true,
arrayFilters: [
{
"elem._id": "5f980a84c4b0d52950bdf90a"
}
]
})```
Here is the mongo query.
db.collection.update({
"lecture_id": "451",
"course_id": "5002",
"message._id": "5f980a84c4b0d52950bdf91a"
},
{
"$inc": {
"message.$.likes": 1
}
})
Try it here Mongo Playground
Not an expert in nodejs. Below update statement may work for you.
let update = { $inc: { "message.$.likes": 1 } }

how to push element into array inside array in mongodb while updating the sibling field of parent array in document

Hell devs, Here is my document schema
var Schema = mongoose.Schema;
var botSchema = new Schema({
Bot_name: String,
UserName:String,
Modules: [{
ModuleStatement: String,
ModuleID: String,
ModuleResponse: [{
Response: String,
TransBotID: String
}]
}]
});
what i want to do is update the ModuleStatement as well as push the element into ModuleResponse setting Response and TransBotID to some values
I tried following but it only updates the ModuleStatement and doesn't push element into ModuleResponse
botSchema.update({ 'Modules.ModuleID': req.body.ModId }, { '$set': { 'Modules.$.ModuleStatement': req.body.Statement } }, function (err, data) {
if (err) {
throw err;
} else {
botSchema.update({ "Modules.ModuleID": req.body.ModId }, { "$push": { "ModuleResponse": { "Response": req.body.Statement, "TransBotID": req.body.transitmod } } }, function (err, data) {
if (err) {
throw err;
}
else {
res.json('upgraded');
}
})
}
})
how can i push element into ModuleResponse while setting the ModuleStatement at the same time?
$push is only available in the $group stage. You may want to try as the following:
botSchema.find({'Modules.ModuleID': req.body.ModId}, (err, bots) => {
if (err) {
throw err;
} else {
bots.forEach((bot) => {
bot.modules.forEach((botModule) => {
if (botModule.ModuleID == req.body.ModId) {
botModule.Statement = req.body.Statement;
botModule.ModuleResponse.push({
Response: req.body.Statement,
TransBotID: req.body.transitmod
})
}
});
bot.save((err, data) => {
if (err) throw err;
});
});
res.json('upgraded');
}
})
Here you have a shell code:
db.bot.update(
{ "Modules.ModuleID": "<some_id>" },
{
"$set": { "Modules.$.ModuleStatement": "<some_statement>" },
"$push": {
"Modules.$.ModuleResponse": {
"Response" : "<some_response>",
"TransBotID" : "<some_trans_id>"
}
}
}
)
The thing is that you can have more than one update expressions in one update document. I believe you can convert it to mongoose quite easily.

nodejs how can i use multidimensional array and push values in it?

i am trying to create a new multidimensional array from the data i am getting from 3rd part API.
"output":[
{
"is_indb":false,
"name":"adam",
"tokens":29
},
{
"is_indb":true,
"name":"aaron",
"tokens":2,
},
{
"is_indb":false,
"name":"adam",
"tokens":3,
},
{
"is_indb":false,
"name":"axel",
"tokens":5,
},
{
"is_indb":false,
"name":"andy",
"tokens":5,
},
{
"is_indb":false,
"name":"bob",
"tokens":5,
},
{
"is_indb":false,
"name":"aldo",
"tokens":5,
},
{
"is_indb":false,
"name":"julia",
"tokens":5,
}
]
i would like to create a new array and fill it with data from response.
but i would like to do some pre checks like
take only those whose, is_indb = false
take only those whose, name starts with a
so the final array will be, all those whosse is_indb = true and name starts with a
var newaray = [[adam,29],[adam,3],[axel,5],[andy,5],[aldo,5]];
so far i have tried using _pluck and getting some weird outputs. i am able to get sible elements using _pluck but cant get multiple items.
i can think of logic like this
var newaray = [];
if( (_pluck(msg.output,'is_indb') == false && ((_pluck(msg.output,'name').substring(0, 1) == "a")){
newaray.push( [ _.pluck(msg.output, 'name') , _.pluck(msg.output, 'token')] );
}
Use filter and map:
var filteredOutput = output
.filter(function(elem) {
// The return statement should return true,
// if you want the element to pass into the new array.
return elem.is_indb === false && typeof elem.name === "string" && elem.name.indexOf('a') === 0;
})
.map(function(elem) {
return [elem.name, elem.tokens];
});
or with ES6:
let filteredOutput = output
.filter(elem => elem.is_indb === false && typeof elem.name === "string" && elem.name.indexOf('a') === 0)
.map(elem => [elem.name, elem.tokens])
with ES6 and using regex (inspired by Peter Grainger's answer, but also case insensitive):
let filteredOutput = output
.filter(elem => elem.is_indb === false && /^a/i.test(elem.name))
.map(elem => [elem.name, elem.tokens])
and by the way, what you posted is an array of objects, not a multidimensional array, which is an array of arrays.
You could use a filter then a map?
const output = [
{
"is_indb":false,
"name":"adam",
"tokens":29
},
{
"is_indb":true,
"name":"aaron",
"tokens":2,
},
{
"is_indb":false,
"name":"adam",
"tokens":3,
},
{
"is_indb":false,
"name":"axel",
"tokens":5,
},
{
"is_indb":false,
"name":"andy",
"tokens":5,
},
{
"is_indb":false,
"name":"bob",
"tokens":5,
},
{
"is_indb":false,
"name":"aldo",
"tokens":5,
},
{
"is_indb":false,
"name":"julia",
"tokens":5,
}
]
const transform = output.filter(value => /^a/.test(value.name) && !value.is_indb)
.map(value => [value.name, value.tokens])
console.log(transform)
You can use _.filter and get the output in this form
op = [{ obj1 } ,{obj2}];
but as you want to remove some keys also then you can use _.pick
var op = _.filter(ip , function(obj){
if(obj.is_indb == false && obj.name[0] == 'a'){
return true;
}
else{
return false;
}
})
//so now you have all the entries filtered out
var opAltered = _.pick(op,['name','tokens']);
//you will get this result
/*
opAltered = [
{
name : <something>,
tokens : <something>
},{
...
}
]
*/
or If you want array you can use this
opAltered = _.map(op,['name','tokens'];
I have used more code to make you understand properly you can reduce it once you understand Thanks.

How to write an if statement to check whether any item in array is greater than a specific value/date?

So, I have a function which should be executed in case that a if condition is true. I simply do not know how to implement it in a method. I have the following code:
Meteor.methods({
'popItems': function () {
var date = new Date().getTime();
if ( "check if this.userId && any item in the array 'itemIds' is $gt date" ) {
userManagement.update({
'_id': this.userId
}, {
$pop: {'itemIds': -1}
}
}
);
};
}
});
So, in case the if condition is true, the $pop function should be executed. In case false, it should not. I wrote this for the if clause, but it doesn't work:
if (this.userId && userManagement.find({
'itemIds': {$gt: date}})) {...$pop function...}
Meteor.methods({
'popItems': function () {
var date = new Date().getTime();
if (this.userId && userManagement.find({'itemIds':{ $gt: date}}).count() > 0 ) {
userManagement.update({
'_id': this.userId
}, {
$pop: {'itemIds': -1}
});
}
};
});
Include the query in the update operation as
Meteor.methods({
'popItems': function () {
var date = new Date();
userManagement.update(
{
'_id': this.userId,
'itemIds': { '$gt': date }
},
{ '$pop': { 'itemIds': -1 } }
);
}
});
I've made some assumptions in coming up with the above solution. The first one being itemIds is an array composed of just Date objects e.g.
itemIds: [
ISODate("2017-01-25T06:20:00.000Z"),
ISODate("2017-01-26T06:20:00.000Z"),
ISODate("2017-01-27T06:20:00.000Z"),
...
ISODate("2017-02-25T06:20:00.000Z")
]
The above query in the update operation can also be specified with an $and operator as:
Meteor.methods({
'popItems': function () {
var date = new Date();
userManagement.update(
{
'$and': [
{ '_id': this.userId },
{ 'itemIds': { '$gt': date } },
]
},
{ '$pop': { 'itemIds': -1 } }
);
}
});

MongoDB: how can I find and merge array

I'm trying to find a specific ID in my document and then merge an array to the existing one, for example if I have this array stored in db.friends:
["12","13","14"]
and I send this array: ["12","16","18"], db.friends should contain: ["12","13","14","16","18"]
I'm using underscore library, but I'm not sure I have to (maybe "aggregate" in mongoose?)
Here is what I did, can you tell me where am I wrong?
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.findOne({_id: req.user._id}).exec(function (err, user) {
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
friends = _.extend(friends, user.friends); //user.friends=existing friends we have in db
user.save(function (err) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW:"+JSON.stringify(friends)); //Here I don't see the merge, also, I can't see it in mongo db.
res.jsonp("success");
});
}
});
Thank you!
With your current implementation, you haven't actually modified the friends key in the returned user object. So rather you can use the union method as
user.friends = _.union(friends, user.friends); //user.friends=existing friends
user.save(function (err) { .. }
Or with ES6 using the spread operator for concatenating the array and Set for creating a distinct set of elements:
user.friends = [...new Set([...friends ,...user.friends])];
user.save(function (err) { .. }
Another alternative is using the aggregation framework, you could utilize the $setUnion operator:
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.aggregate([
{ "$match": { _id: req.user._id } },
{
"$project": {
"friends": { "$setUnion": [ "$friends", friends ] }
}
}
]).exec(function (err, results){
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
User.findByIdAndUpdate(req.user._id,
{ "$set": { "friends": results[0].friends } },
{ "new": true },
function (err, user) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW: "+ JSON.stringify(user.friends));
res.jsonp("success");
}
);
}
});
}

Resources