I have an array of objects in the form below. Each object represents the result of a soccer game. The actual array contains far more records than what I have here. In each game, the team (home or away) that has the highest corresponding score gets 3 points and the team with the lowest score gets 0 points. If the scores are the same, each team gets 1 point. I want to create logic that aggregates the points for each unique team whether they are home or away. I would like to see different types of options (newer syntax, etc), but especially a vanilla javascript solution.
I plan to work through it as well, but I'm struggling to come up with anything succinct.
[{
"_id" : ObjectId("5a4824f3a469a068edc875e2"),
"homeTeam" : "Team1",
"homeScore" : 2,
"awayTeam" : "Team2",
"awayScore" : 1,
}
{
"_id" : ObjectId("5a4824f3a469a068edc894e9"),
"homeTeam" : "Team2",
"homeScore" : 2,
"awayTeam" : "Team3",
"awayScore" : 1,
},{
"_id" : ObjectId("5a4824f3a469a068edc554e7"),
"homeTeam" : "Team4",
"homeScore" : 1,
"awayTeam" : "Team5",
"awayScore" : 1,
}]
var data = [{
"_id" : "5a4824f3a469a068edc875e2",
"homeTeam" : "Team1",
"homeScore" : 2,
"awayTeam" : "Team2",
"awayScore" : 1,
},
{
"_id" : "5a4824f3a469a068edc894e9",
"homeTeam" : "Team2",
"homeScore" : 2,
"awayTeam" : "Team3",
"awayScore" : 1,
},{
"_id" : "5a4824f3a469a068edc554e7",
"homeTeam" : "Team4",
"homeScore" : 1,
"awayTeam" : "Team5",
"awayScore" : 1,
}];
var teamStats = {};
var i = 0;
for(;i < data.length; i++) {
// New Home team
if(teamStats[data[i].homeTeam] == undefined) {
teamStats[data[i].homeTeam] = {
name: data[i].homeTeam,
score: 0
}
}
// New Away team
if(teamStats[data[i].awayTeam] == undefined) {
teamStats[data[i].awayTeam] = {
name: data[i].awayTeam,
score: 0
}
}
// Update score
teamStats[data[i].homeTeam].score += data[i].homeScore;
teamStats[data[i].awayTeam].score += data[i].awayScore;
}
// teamStats contains a scores of all teams
Related
How to create collection in mongodb with specific uuid or update the uuid ?
db.runCommand( { listCollections: 1.0 })
"uuid" : UUID("8d1e5add-9e49-4ff5-af4f-abf12e40b078")
Adding details:
When I create a collection mongodb generate automatically uuid and if this is replicaSet the uuid is replicated to all SECONDARY members via the oplog:
PRIMARY> use test
PRIMARY> db.createCollection("theTest")
PRIMARY> use local
PRIMARY> db.oplog.rs.find({}).sort({$natural:-1})
{ "ts" : Timestamp(1632477826, 1), "t" : NumberLong(56), "h" : NumberLong("8154379731463656698"), "v" : 2, "op" : "c", "ns" : "test.$cmd", "ui" : UUID("7710a307-020a-48bf-916c-db94544f8586"), "wall" : ISODate("2021-09-24T10:03:46.145Z"), "o" : { "create" : "theTest", "idIndex" : { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.theTest" } } }
But I would like to know if there is an option this UUID to be created with command or updated ?
Maybe there is an option to apply oplog entry with modified UUID?
Thanks,
I have found the answer, for those who are interested here is the solution:
var uuid = UUID("a6c3c5c8-8424-4a06-96a1-4082c349c6f1");
var ops = [{ "op": "c","ns": "test.$cmd","ui": uuid,"o": {"create": "newTest","idIndex": {"v": 2, "key": {"_id": 1}, "name": "_id_", "ns": "test.newTest"} } }];
db.adminCommand({applyOps: ops});
I am using Stitch platform by MongoDB. I want to store a value and a count associated with that value in the database. Now the value may not be present for the first time, so I would like to insert the value with count = 1.
I can use update() to update the existing value of count using $inc or I can use upsert() to add the value in the database.
Now, the thing is, I have a map of my values and the count, and I want to insert(update/upsert) all at once. I don't want to put a load on the network.
I was using insertMany() to insert the map at once but it clearly doesn't updates the value.
So is it possible to do so?
P.S. I am using javascript for the same.
According to MongoDb 3.6:
db.collection.update(query, update, options)
Modifies an existing document or documents in a collection. The method can modify specific fields of an existing document or documents or replace an existing document entirely, depending on the update parameter.
The meaning is that you can upsert multiple documents using update.
First you should create array from your map that contains only the value.
const arrayOfValues = ['value_01', 'values_02'];
Then you should use the upsert + multi options on the update method:
db.foo.update({value: { $in: arrayOfValues}}, {$inc: {count:1}}, { upsert: true, multi: true });
Test output:
> db.createCollection("test");
{ "ok" : 1 }
> db.test.insertMany([{value: "a"}, {value: "b"}, {value: "c"}];
... );
2017-12-31T12:12:18.040+0200 E QUERY [thread1] SyntaxError: missing ) after argument list #(shell):1:61
> db.test.insertMany([{value: "a"}, {value: "b"}, {value: "c"}]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5a48b8061b98cc5ac252e435"),
ObjectId("5a48b8061b98cc5ac252e436"),
ObjectId("5a48b8061b98cc5ac252e437")
]
}
> db.test.find();
{ "_id" : ObjectId("5a48b8061b98cc5ac252e435"), "value" : "a" }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e436"), "value" : "b" }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e437"), "value" : "c" }
> db.test.update({value: { $in: ["a", "b", "c"]}}, {$inc: {count:1}}, { upsert: true, multi: true });
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
> db.test.find();
{ "_id" : ObjectId("5a48b8061b98cc5ac252e435"), "value" : "a", "count" : 1 }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e436"), "value" : "b", "count" : 1 }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e437"), "value" : "c", "count" : 1 }
> db.test.update({value: { $in: ["a", "b", "c"]}}, {$inc: {count:1}}, { upsert: true, multi: true });
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
> db.test.find();
{ "_id" : ObjectId("5a48b8061b98cc5ac252e435"), "value" : "a", "count" : 2 }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e436"), "value" : "b", "count" : 2 }
{ "_id" : ObjectId("5a48b8061b98cc5ac252e437"), "value" : "c", "count" : 2 }
> db.test.update({value: { $in: ["a", "b", "c"]}}, {$inc: {count:1}}, { upsert: true, multi: true });
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
Hope it was helpful :)
I want to create an output array which takes all the parameters from its subarray and create a resulting array.
Hard to explain in words, so am explaining with an example below.
var myArr=[
{
"Id":1,
"Name":'Ken',
"Age" : '30',
"Hobbies" : [{'HobbyId':1,'HobbyName':'Swimming'},{'HobbyId':2,'HobbyName':'Reading'}],
"Skills" : [{'SkillId':1,'SkillName':'PHP'},{'SkillId':2,'SkillName':'MySQL'}],
"Language" : [{'LangId':2,'LangName':'English'},{'LangId':3,'LangName':'Chinese'}]
},
{
"Id":2,
"Name":'Mike',
"Age" : '20',
"Hobbies" : [],
"Skills" : [],
"Language" : []
},
{
"Id":3,
"Name":'Charlie',
"Age" : '25',
"Hobbies" : [{'HobbyId':5,'HobbyName':'Dance'},{'HobbyId':6,'HobbyName':'Sing'},{'HobbyId':7,'HobbyName':'Writing'}],
"Skills" : [],
"Language" : [{'Id':7,'Name':'English'}]
}
]
In the above example there are 3 subarrays named Hobbies, Skills and Languages.
I'll have some more subarrays apart from these three.
I actually want to remove the subarray logic and make it a flat array.
So, when creating this flat array I want to consider all the parameters from subarray even if the subarray is empty.
So my first item of resulting array will have the first item of all subarrays and so on.
Even if the subarray is an empty array I need to consider there keys and input the value as null.
And so my resulting array will be as below :
var resultArray = [
{
"Id":1,
"Name":'Ken',
"Age" : '30',
"HobbyId" : 1,
"HobbyName" : 'Swimming',
"SkillId" : 1,
"SkillName":'PHP',
"LangId" : 2,
"LangName" : 'English'
},
{
"Id":1,
"Name":'Ken',
"Age" : '30',
"HobbyId" : 2,
"HobbyName" : 'Reading',
"SkillId" : 2,
"SkillName":'MySQL',
"LangId" : 3,
"LangName" : 'Chinese'
},
{
"Id":2,
"Name":'Mike',
"Age" : '20',
"HobbyId" : '',
"HobbyName" : '' ,
"SkillId" : '',
"SkillName":'',
"LangId" : '',
"LangName" : ''
},
{
"Id":3,
"Name":'Charlie',
"Age" : '25',
"HobbyId" : 5,
"HobbyName" : 'Dance',
"SkillId" : '',
"SkillName":'',
"LangId" : 7,
"LangName" : 'English'
},
{
"Id":3,
"Name":'Charlie',
"Age" : '25',
"HobbyId" : 6,
"HobbyName" : 'Sing',
"SkillId" : '',
"SkillName":'',
"LangId" : '',
"LangName" : ''
},
{
"Id":3,
"Name":'Charlie',
"Age" : '25',
"HobbyId" : 7,
"HobbyName" : 'Writing',
"SkillId" : '',
"SkillName":'',
"LangId" : '',
"LangName" : ''
}
]
This seems to produce what you wanted:
let results = [];
for(let {Id, Name, Age, Hobbies, Skills, Language} of myArr) {
let numRows = Math.max(1, Hobbies.length, Skills.length, Language.length);
for (let i=0; i<numRows; i++) {
let {HobbyId, HobbyName} = Hobbies[i] || {};
let {SkillId, SkillName} = Skills[i] || {};
let {LangId, LangName} = Language[i] || {};
results.push({
Id, Name, Age,
HobbyId, HobbyName,
SkillId, SkillName,
LangId, LangName,
});
}
}
console.table(results);
The non-trivial bits are:
I use quite a bit of ES6 syntax. You might want to read a bit more about object destructuring, shorthand object literals and for..of.
I calculate the number of rows needed before starting iteration so that I don't have to check every time whether I should go to the next person or not.
I do Hobbies[i] || {} in order to make sure that I always have an object to desctructure with let {HobbyId, HobbyName}. I do it this way because it's simpler than checking for null each time.
i need to aggregate my data. this would be easy if i use mongodb aggregation,, but i want to perform in client side. LoDash or Underscore should solve this...
suppose i have this data:
var data = [
{
"uId" : "u1",
"qId" : "q1",
"share" : 2,
"star" : 2,
"score" : 5
},
{
"uId" : "u1",
"qId" : "q2",
"share" : 2,
"star" : 2,
"score" : 5
}.
{
"uId" : "u2",
"qId" : "q1",
"share" : 2,
"star" : 2,
"score" : 5
},
{
"uId" : "u2",
"qId" : "q2",
"share" : 3,
"star" : 3,
"score" : 7
},
{
"uId" : "u3",
"qId" : "q1",
"share" : 3,
"star" : 3,
"score" : 7
},
{
"uId" : "u3",
"qId" : "q2",
"share" : 3,
"star" : 3,
"score" : 7
}
]
i need this result:
result = [
{
"uId" : "u3",
"qId" : 2,
"share" : 6,
"star" : 6,
"score" : 14
},
{
"uId" : "u2",
"qId" : 2,
"share" : 5,
"star" : 5,
"score" : 12
}
]
it sort by highest score and limit the result to only show 2 results
thank You...
You could also do this in underscore.
_.sortBy(data, 'score').reverse().splice(0, 2);
not sure how performant the reverse would be though.
EDIT:
got it without the reverse:
_.sortBy(data, function (el) { return -el.score; }).splice(0, 2);
You can use lodash for it :
_.map(_.sortByOrder(data, ['score'], ['desc']), _.values).slice(0,2);
First it will create a sorted array and then limit the result to have only two results.
I have the following User object:
{
"_id" : ObjectId("someId"),
"name" : "Bob",
"password" : "fakePassword",
"follower" : [...],
"following" : [..]
}
I need to paginate over the follower list, so I use the slice projection operator, but I just need the paginated followers list to be returned. And I don't know if I am doing it the wrong way, or this can't be done, but limit fields doesn't work with slice projection.
Following are a couple of queries I tried:
collection.findOne(
{
_id: new ObjectId(userId)
},
{
follower: {$slice:[skip, parseInt(pageSize)]},
follower: 1
},..
and
collection.findOne(
{
_id: new ObjectId(userId)
},
{
follower: 1,
follower: {$slice:[skip, parseInt(pageSize)]}
},
But these return all the values in the object, and does not limit the fields, although, the slice works fine in both the cases.
Also when I do something like _id:0,following:0 , this part works, but I don't want to mention each and every field in the query like this, it may create problems once I decide to change the schema.
How do I get this to work, what could be the syntax for the query to get this working..??
Not sure I'm getting your usage pattern here. Perhaps we can simplify the example a little. So considering the document:
{
"_id" : ObjectId("537dd763f95ddda3208798c5"),
"name" : "Bob",
"password" : "fakePassword",
"follower" : [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K"
]
}
So the simple query like this:
db.paging.find(
{ "name": "Bob" },
{
"_id": 0,
"name": 0,
"password": 0,
"follower": { "$slice": [0,3] }
}).pretty()
Gives results:
{
"follower" : [
"A",
"B",
"C"
]
}
And similarly from the following page:
db.paging.find(
{ "name": "Bob" },
{
"_id": 0,
"name": 0,
"password": 0,
"follower": { "$slice": [3,3] }
}).pretty()
Gives the results:
{
"follower" : [
"D",
"E",
"F"
]
}
So for me personally I am not sure whether you were asking about the field exclusion or whether you were asking about "paging" the array results, but either way, both of those examples are shown here.
One way is to actually use _id here by saying {_id:1}:
{ "_id" : ObjectId("537de1bc08eb9d89a7d3a1b2"), "f" : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20 ], "d" : 1 }
> db.test.findOne({ "_id" : ObjectId("537de1bc08eb9d89a7d3a1b2")},{f:{$slice:[0,2]}})
{
"_id" : ObjectId("537de1bc08eb9d89a7d3a1b2"),
"f" : [
1,
2
],
"d" : 1
}
> db.test.findOne({ "_id" : ObjectId("537de1bc08eb9d89a7d3a1b2")},{_id:0, f:{$slice:[0,2]}})
{ "f" : [ 1, 2 ], "d" : 1 }
> db.test.findOne({ "_id" : ObjectId("537de1bc08eb9d89a7d3a1b2")},{_id:1, f:{$slice:[0,2]}})
{ "_id" : ObjectId("537de1bc08eb9d89a7d3a1b2"), "f" : [ 1, 2 ] }