Ordering the JSON data with JavaScript - javascript

I'm looking way to order data wich is coming from my JSON Provider:
[{"Username":"Mehmet","UserID":2,"OkeyTablePlayerChairNumber":1},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":2},
{"Username":"Erçin","UserID":1,"OkeyTablePlayerChairNumber":3},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":4},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":5},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":6},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":7},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":8},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":9}]
There is two more important thing for ordering:
OkeyTablePlayerChairNumber
By UserID First; let me explain:
I want to order them firstly by OkeyTableChairNumber; this is done by Server Side already. Data coming ordered by OkeyTablePlayerChairNumber ASC...
Now the bull,
I would like to order them by UserID but; for example if I took UserID == 1 it should order them like: UserID == 1 field, will be come to first field. and upper objects will removed and added to end of the list...
For view:
UserID == 1
[{"Username":"Erçin","UserID":1,"OkeyTablePlayerChairNumber":3},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":4},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":5},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":6},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":7},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":8},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":9},
{"Username":"Mehmet","UserID":2,"OkeyTablePlayerChairNumber":1},
{"Username":null,"UserID":0,"OkeyTablePlayerChairNumber":2}]
C# Solution I made before; But I need JS solutions:
int yourSitPositionIndex = playersOnTheTableWithEmpytPositions.ToList().FindIndex(x => x.UserID == userID);
var beforePlayers = playersOnTheTableWithEmpytPositions.ToList().GetRange(0, yourSitPositionIndex);
IEnumerable<tbl_Okey_TablePlayer> afterPlayers = playersOnTheTableWithEmpytPositions.Except(beforePlayers);
IEnumerable<tbl_Okey_TablePlayer> newPositions = afterPlayers.Concat(beforePlayers);

Conversion of your C# solution:
var wantedId = 1;
var index = 0, result;
//int yourSitPositionIndex = playersOnTheTableWithEmpytPositions.ToList().FindIndex(x => x.UserID == userID);
while (index < data.length && data[index].UserID != wantedId) index += 1;
if (index < data.length) {
//var beforePlayers = playersOnTheTableWithEmpytPositions.ToList().GetRange(0, yourSitPositionIndex);
var beforePlayers = data.slice(0, index);
//IEnumerable<tbl_Okey_TablePlayer> afterPlayers = playersOnTheTableWithEmpytPositions.Except(beforePlayers);
var afterPlayers = data.slice(index);
//IEnumerable<tbl_Okey_TablePlayer> newPositions = afterPlayers.Concat(beforePlayers);
result = afterPlayers.concat(beforePlayers);
} else {
result = data;
}
There is no FindIndex in the core of javascript, so I did a while loop to find the index
I use .slice() to replace GetRange
Rest of the code should be clear enough. The all code could be simplified with libraries like underscore
Example fiddle

If the goal is to order by UserID DESC, OkeyTable... ASC
You can define a customer sort function:
In action: http://repl.it/XZm
var json = [/*all your data */]
function idSort(a,b){
if(a["UserID"] !== b["UserID"]){
return b["UserID"] - a["UserID"];
} else {
return a["OkeyTablePlayerChairNumber"] - b["OkeyTablePlayerChairNumber"];
}
}
var sorted = json.sort(idSort);
Results:
[ { Username: 'Mehmet', UserID: 2, OkeyTablePlayerChairNumber: 1 },
{ Username: 'Erçin', UserID: 1, OkeyTablePlayerChairNumber: 3 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 2 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 4 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 5 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 6 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 7 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 8 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 9 } ]
Here is UserID ASC, OkeyTable...ASC:
function idSort(a,b){
var notZero = (a["UserID"] > 0 && b["UserID"] > 0);
var notEqual = (a["UserID"] !== b["UserID"]);
if(notZero && notEqual){
return a["UserID"] - b["UserID"];
} else {
return a["OkeyTablePlayerChairNumber"] - b["OkeyTablePlayerChairNumber"];
}
}
var sorted = json.sort(idSort);
Results:
[ { Username: 'Erçin', UserID: 1, OkeyTablePlayerChairNumber: 3 },
{ Username: 'Mehmet', UserID: 2, OkeyTablePlayerChairNumber: 1 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 2 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 4 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 5 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 6 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 7 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 8 },
{ Username: null, UserID: 0, OkeyTablePlayerChairNumber: 9 } ]
In action: http://repl.it/XZm/1

Related

Add new field to report - Script - NodeJS and MongoDB

I have to run a report from a script.
The script works fine
Need to add a new field that indicates if the user is admin or not.
I am not sure how to add that with a true or false condition.
Right now it is returning undefined or false.
The field in mongo database is this one:
mongo-database
var orderTotalsByUserId = {};
db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).forEach( d => orderTotalsByUserId[d._id.userId] = d.total )
var userIdsByOrders = db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).map( d => ObjectId(d._id.userId) )
var customers = {};
db.organizations.find().forEach(c => { customers[c._id.valueOf()] = c });
db.users.find({ _id: { $in: userIdsByOrders } }).forEach(d => print(`${d.firstName}, ${d.lastName}, ${d.profile.email}, ${customers[d.customerId].name},${d.sensitive.active.globalAdmin}, ${(orderTotalsByUserId[d._id.valueOf()] * .01).toFixed(2)}`) )
After some time, I've been able to solve it.
Hope it can be helpful for someone else.
First filtering the featurePermissions field in the pipeline.
Then, created an if statement, indicating that if the user has a Customer, it should print the following values.
The solution was:
var orderTotalsByUserId = {};
db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).forEach( d => orderTotalsByUserId[d._id.userId] = d.total );
var customers = {};
db.organizations.find().forEach(c => { customers[c._id.valueOf()] = c });
db.users.find({ featurePermissions: { $exists: true } }, { _id: 1, firstName: 1, lastName: 1, profile: 1, customerId: 1, featurePermissions: 1 }).forEach(d => { if (customers[d.customerId]) { print(`${d.firstName}, ${d.lastName}, ${d.profile.email}, ${customers[d.customerId].name}, ${orderTotalsByUserId[d._id.valueOf()] ? (orderTotalsByUserId[d._id.valueOf()] * .01).toFixed(2) : 0 }, ${d.featurePermissions.user_management ? 'true' : 'false' }`)}});

Filter nested array in object javascript express

Considering the below object:
[
{
id: 5fc0be2990a8a12cc0ba0b5c,
projectName: 'E-271120-B',
projectManagaer: '5f7f1ba973ff621da4322248',
dataInici: 2020-11-26T23:00:00.000Z,
dataEntrega: 2020-11-26T23:00:00.000Z,
dtoGlobal: null,
dtoProjecte: null,
archived: false,
created: 2020-11-27T08:51:57.242Z,
updated: 2021-01-25T10:01:18.733Z
tabs: [{permissionsUserID:[250,8]},{permissionsUserID:[3]}],
__v: 3
},
{
tabs: [{permissionsUserID:[3,350]},{permissionsUserID:[15]}],
_id: 5fc0be4690a8a12cc0ba0b5f,
projectManagaer: '5f7f0e69b5862e1a085db388',
projectName: 'E-271120-C',
dataInici: 2020-11-27T23:00:00.000Z,
dataEntrega: 2020-11-29T23:00:00.000Z,
dtoGlobal: null,
dtoProjecte: null,
archived: false,
created: 2020-01-21T08:46:41.958Z,
updated: 2021-01-21T08:46:41.958Z,
__v: 2
},
{
tabs: [{permissionsUserID:[31,350]},{permissionsUserID:[8,893]}],
_id: 5fc0be4690a8a12cc0ba0b5f,
projectManagaer: '5f7f0e69b5862e1a085db388',
projectName: 'E-23410-C',
dataInici: 2020-11-27T23:00:00.000Z,
dataEntrega: 2020-11-29T23:00:00.000Z,
dtoGlobal: null,
dtoProjecte: null,
archived: false,
created: 2020-01-21T08:46:41.958Z,
updated: 2021-01-21T08:46:41.958Z,
__v: 2
}
]
Each object represents a Project. A project has many tabs.
I want to return only the projects that at least one tab contains in permissionsUserID the ID of the user that is logged.
So if the user that is logged has the ID 8, these are the projects I want to obtain:
[
{
id: 5fc0be2990a8a12cc0ba0b5c,
projectName: 'E-271120-B',
projectManagaer: '5f7f1ba973ff621da4322248',
dataInici: 2020-11-26T23:00:00.000Z,
dataEntrega: 2020-11-26T23:00:00.000Z,
dtoGlobal: null,
dtoProjecte: null,
archived: false,
created: 2020-11-27T08:51:57.242Z,
updated: 2021-01-25T10:01:18.733Z
tabs: [{permissionsUserID:[250,8]},{permissionsUserID:[3]}],
__v: 3
},
{
tabs: [{permissionsUserID:[31,350]},{permissionsUserID:[8,893]}],
_id: 5fc0be4690a8a12cc0ba0b5f,
projectManagaer: '5f7f0e69b5862e1a085db388',
projectName: 'E-23410-C',
dataInici: 2020-11-27T23:00:00.000Z,
dataEntrega: 2020-11-29T23:00:00.000Z,
dtoGlobal: null,
dtoProjecte: null,
archived: false,
created: 2020-01-21T08:46:41.958Z,
updated: 2021-01-21T08:46:41.958Z,
__v: 2
}
]
That's the filter I have done:
async getAll(pagination, user) {
try {
const filter = {};
if(pagination.archived) {
filter['archived'] = pagination.archived;
}
if(pagination.search) {
filter['$text'] = {$search: pagination.search}
}
const { Project: projectSchema } = this.getSchemas();
const projectsDocs = await projectSchema.paginate(filter, {
limit: pagination.limit ? parseInt(pagination.limit) : 10,
page: pagination.page ? parseInt(pagination.page) + 1 : 1
});
if (!projectsDocs) {
throw new errors.NotFound('No Projects.');
}
projectsDocs.docs.forEach(element => {
element.tabs.filter( d => d.permissionsUserID.every( c => c.includes(user._id)));
});
return projectsDocs;
} catch (error) {
throw error;
}
},
Here is one way
const data = [...];
const userId = 8;
const result = data.filter((item) => {
const {tabs} = item;
let loggedIn = false;
tabs.forEach((tab) => {
if (tab.permissionsUserID.includes(userId)) {
loggedIn = true;
return true
}
})
return loggedIn;
})
Here's a simple function which should get you what you want.
Filter() returns a subset of the projects list. Some() returns true if at least one of the tabs has the value we're looking for. Includes() returns true if the permissionsUserId list has the user id we want. Chain those together and you get the subset of projects where a tab's permissions has the desired user id.
const data = [
/* list of projects */
],
userId = 8;
function getProjectsForUserId (data, userId) {
return data.filter((project) => {
return project.tabs.some((tab) => {
return tab.permissionsUserID.includes(userId);
});
});
}
console.log(getProjectsForUserId(data, 8));

Angular & Mongo query , return result closely equal to related to the search keyword

If text(firstname) == 'Eric' , it should return results . Any idea how we can tweek my code to return result as expected on the example ?
I am using angular on the front-end.
#Expected result (this would be top on the result)
Eric Gluthner
Eric Lecher
Erick Laspin
#and the other names with eric which would be less prio
Derick Ramp
Daniel Ericto
Raerick Fouler
#Code
getData(text: string): Observable<Identity[]> {
const search_query = {
query: {
$or: [
{ firstName: { $like: text } },
{ email: { $like: text } },
],
status: 1,
$sort: {
firstName: 1
},
// $limit: 5,
}
};
Using $regex pattern matching
getData(text: string): Observable<Identity[]> {
const search_query = {
query: {
$or: [
{ firstName: { $regex: RegExp('^' + text) } },
{ email: { $like: text } },
],
status: 1,
$sort: {
firstName: 1
},
// $limit: 5,
}
};

how to count length of aggregate before skip(pagination)

I am building an api to get details of jobs and I need to do pagination for it. For pagination I need to get total number of pages, but I'm getting only skip pages. Please help me to get total number of pages before skip.
let cJobs = await CrewbiesJobs.GetAllJobs();
let flashJobsResult = [];
let totalPages = 0;
let filter = {};
let queryLimit = parseInt(req.query.limit) || 10;
let pageNo = parseInt(req.query.page) || 1;
let query = {};
if (pageNo < 0 || pageNo === 0) {
throw new CustomError('invalid page number, should start with 1', HttpStatus.BAD_REQUEST);
}
query.skip = req.query.limit * (pageNo - 1) || 1;
query.limit = queryLimit;
let jobsAggregate = await Jobs.aggregate([{
$lookup: {
from: CrewbiesJobs.collection.name,
localField: "jobId",
foreignField: "jobId",
as: "job_docs"
}
},
{
$unwind: "$job_docs"
},
{
$project: {
_id: 1,
jobTitle: 1,
jobId: 1,
jobDescription: 1,
postedDate: 1,
filter1: 1,
filter2: 1,
filter3: 1,
createdAt: 1,
updatedAt: 1
}
},
{
$match: filter
},
{
$skip: query.skip
},
{
$limit: query.limit
}
]).exec(function(err, doc) {
if (err) {
res.send(err);
} else {
totalPages = Math.ceil(doc.length / queryLimit);
if (pageNo > totalPages) {
throw new CustomError('Invalid page number', HttpStatus.BAD_REQUEST);
}
console.log('matched jobs ', doc.length);
res.json({
msg: 'Jobs listed successfully',
item: {
totalPages: doc.length,
currentpage: pageNo,
jobs: doc
},
jobsCount: doc.length
});
}
});
}
catch (err) {
CustomError.Handle(err, res);
}
totalPages counts should return 21 but am getting only 10 instead:
*{
"msg": "Jobs listed successfully",
"item": {
"totalPages": 10,
"currentpage": 1,
},
"jobsCount": 10
}*
An option to make a single trip to db and get the count of documents is to use $facet which allows to process multiple aggregation pipelines. Since $count wouldn't work with $addFields or $project in conjunction with the actual pipeline result.
Query: (After unwinding the job_docs do $facet stage)
Jobs.aggregate([
{
$lookup: {
from: CrewbiesJobs.collection.name,
localField: "jobId",
foreignField: "jobId",
as: "job_docs"
}
},
{
$unwind: "$job_docs"
},
{
$facet: {
totalDocs: [
{
$count: "value"
}
],
pipelineResult: [
{
$project: {
_id: 1,
jobTitle: 1,
jobId: 1,
jobDescription: 1,
postedDate: 1,
filter1: 1,
filter2: 1,
filter3: 1,
createdAt: 1,
updatedAt: 1
}
},
{ $match: filter },
{ $skip: query.skip },
{ $limit: query.limit }
]
}
},
{ $unwind: "$totalDocs" }
]).exec();
Resultant Document: Demo
{
"totalDocs" : {
"value" : 44
},
"pipelineResult" : [
{
"_id" : ObjectId("5da7040e45abaee927d2d11a"),
"jobTitle" : "Foo",
"jobDescription": "Bar",
...
"job_docs" : {...}
},
...
]
}
Where totalDocs contain the count of documents in value property and pipelineResult would contain the documents of main pipeline operations.
As far as I know you need to have a seperate query for total count.
The both aggregations have common stages so first I created the baseStages.
Then I added skip and limit stages to this base stage for the jobs data, and added the count stage to the base stage to get total count of collections.
So you can try something like this:
const baseStages = [
{
$lookup: {
from: CrewbiesJobs.collection.name,
localField: "jobId",
foreignField: "jobId",
as: "job_docs"
}
},
{
$unwind: "$job_docs"
},
{
$project: {
_id: 1,
jobTitle: 1,
jobId: 1,
jobDescription: 1,
postedDate: 1,
filter1: 1,
filter2: 1,
filter3: 1,
createdAt: 1,
updatedAt: 1
}
},
{ $match: filter }
];
const jobsStages = [
...baseStages,
{ $skip: query.skip },
{ $limit: query.limit }
];
let jobsAggregate = await Jobs.aggregate(jobsStages);
const countStages = [...baseStages, { $count: "COUNT" }];
let countAggregate = await Jobs.aggregate(countStages);
To construct the response I would console.log(countAggregate), and inspect where the count value resides, and use that value in response.

Ambiguous Unexpected Identifier error

Mongo isn't liking some identifier that I've got in the forEach loop holding the second aggregation, and for the life of me I can't find which one it is. I've been looking at it all day and at this point I just need another pair of eyes on it. My eyes, brain, and heart thank you in advance!
use events
var affected = []
var start = new Date()
var end = new Date("2017-06-01T00:00:00Z")
for (var dayPast = new Date(start); start >= end; start.setDate(start.getDate() - 1)) {
dayPast.setDate(dayPast.getDate() - 1)
var results = db.completion_event.aggregate([{
$match: {
applicationId: 1,
dateCreated: {
$lt: start,
$gte: dayPast
},
"data.name": "eventComplete",
"data.metadata.aggregationId": /identifying_string.*/,
"data.sponsorIds": {$in: [1,2,3,4,5,6]}
}
}, {
$project: {
customerId: 1,
dateCreated: 1,
"data.metadata.aggregationId": 1
}
}, {
$group: {
_id: {
customerId: "$customerId",
dateCreated: "$dateCreated",
aggregationId: "$data.metadata.aggregationId"
},
"total": {
$sum: 1
}
}
}], {
$limit: 1
}, {
allowDiskUse: true
}).toArray()
results.forEach(function(event) {
use rewards
var state = db.customer_state.find({customerId: event._id.customerId}).sort({_id: -1}).limit(1).toArray()[0]
var planId = state.planId
var plan = db.plan.find({id: planId}).toArray()[0]
if(plan.schedule.activeStart < new Date() < plan.schedule.activeEnd) {
use events
var latest = db.completion_event.aggregate([{
$match: {
applicationId: 1,
customerId: event._id.customerId,
dateCreated: {
$gte: plan.schedule.activeStart
},
"data.name": "outterEventComplete",
"data.metadata.aggregationId": event._id.aggregationId
}
},
{
$project: {
consumerId: 1,
dateCreated: 1,
"data.sponsorIds": 1,
"data.metadata.aggregationId": 1
}
}], {
$limit: 1
}).toArray()
affected.push(latest[0])
}
})
}
print(affected)
And the current bane of my existence:
E QUERY SyntaxError: Unexpected identifier
I'm betting on use rewards and use events. Those are shell shortcuts, you're not supposed to use them in the middle of regular javascript code. Here's an alternative:
Instead of switching db via use rewards use this
var rewards_db = db.getSisterDB('rewards');
rewards_db.customer_state.find(...)
Same for events, naturally.

Categories

Resources