I have a collection with a single document that contains many stats of different people.
It is structured like so:
// Stats list:
[{
id: .... ,
lastUpdated: ... ,
stats: {
Person1: {stat1: 0, stat2: 0, stat3: 0},
Person2: {stat1: 0, stat2: 0, stat3: 0},
...
Person100: {stat1: 0, stat2: 0, stat3: 0}
}
}]
These stats are updated every 24 hours.
Now I have a few hundred listings that contain a specific list of the people in the first collection.
// Listings:
[{
id: ...,
persons: {
Person1: {stat1: 0, stat2: 0, stat3: 0},
Person43: {stat1: 0, stat2: 0, stat3: 0}
}
}]
I want to be able to update all person stats in these listings compared to the persons in the stats section in the first collection I showed.
My logic is something along the lines of this:
await Listing.updateMany({}, { $set: { persons: { "some kind of query" } } });
But I am not sure how to most efficiently go about this.
I have the attached document structure. I need to retrieve the document with only some parameter.
For example
I need the data to be like this.
{
"_id": "57f36d71fb1ef61bd84f866b",
"testMaxScore": 235,
"testMaxTime": 60,
"inviteId": "57f0a97d11594560c02a8f43",
"testName": "Sr. Interactive Developer l1",
"sectionList": [
{
"sectionName": "Java MCQ",
"sectionInfo": "Some info",
"questionList": [
{
"_id": "57ea3d003f2ec2cbbe98bbb9",
"question": ""
},
{
"_id": "57ea3d003f2ec2cbbe98bbb9",
"question": ""
}
]
}
]
How can i acheve this ?
I am using mongoose
Can anyone help me on this
Thanks,
Kiran
Possible through the aggregation framework. Consider running an aggregation operation that has a single pipeline with the $project operator to project just the fields you want.
In the above example, you would run it as
Model.aggregate([
{
"$project": {
"testMaxScore": 1,
"testMaxTime": 1,
"inviteId": 1,
"testName": 1
"sectionList.sectionName" : 1,
"sectionList.sectionInfo" : 1,
"sectionList.questionList._id": 1,
"sectionList.questionList.question": 1
}
}
]).exec(function(err, result){
console.log(result);
})
or using the find() method:
Model.find(
{ },
{
"testMaxScore": 1,
"testMaxTime": 1,
"inviteId": 1,
"testName": 1
"sectionList.sectionName" : 1,
"sectionList.sectionInfo" : 1,
"sectionList.questionList._id": 1,
"sectionList.questionList.question": 1
}
).exec(function(err, result){
console.log(result);
})
Try to use the following find expression:
yourSchema.find({}).select('testName inviteId sectionList.sectionName'); // and so on
This is my Schema,
var trainListSchema = new mongoose.Schema({
trainNo: Number,
trainName:String,
fromStation : String,
toStation: String,
runningDays: [{type:Number}],
trainType: String,
createdTime: {type:Date , default:Date.now}})
and this is the function used to insert multiple documents.
createTrainList: function(data) {
trainList.insertMany(data, function(err, post) {
if (err) return next(err);
console.log(post);
});
}
Now as you can se runningDays is an array. While using the above method to insert data. runningDays gets inserted as 0 elements while rest of the field gets inserted successfully.
How should I go about inserting array within array using mongoose.
Help will be appreciated.
Here is the sample JSON.
[
{
"trainNo": "10104",
"trainName": "MANDOVI EXPRESS",
"fromStation": "MAO",
"toStation": "CSTM",
"days": [
0,
1,
2,
3,
4,
5,
6
],
"trainType": "MAIL EXP"
},
{
"trainNo": "10111",
"trainName": "KONKAN KANYA EX",
"fromStation": "CSTM",
"toStation": "MAO",
"days": [
0,
1,
2,
3,
4,
5,
6
],
"trainType": "MAIL EXP"
}]
I'm trying this simple MapReduce operation:
function map() {
var gameDay = Math.floor((this.matchCreation - 1427846400000) / 86400000) + 1; // day of april 2015 when the game was played
this.teams.forEach (function (team){
**team.bans.forEach(function (ban){** // says bans is undefined
var value ={
banned : 1,
firstBanned: ( ((ban.pickTurn == 1) || (ban.pickTurn == 2))? 1 : 0 )
}
emit({championId: ban.championId,
day: Number(gameDay)}, value);
emit({championId: ban.championId,
day: "all"}, value);
});
});
}
function reduce(key, values) {
var a = values[0];
for(var i = 1 ; i<values.length ; i++){
var b = values[i]; // will merge 'b' into 'a'
a.banned += (b.banned? b.banned : 0);
a.firstBanned += (b.firstBanned? b.firstBanned : 0);
for (var attrname in b){
if(attrname != "banned" && attrname != "firstBanned")
a[attrname] = b[attrname];
}
}
return a;
}
matchesCollection.mapReduce(map, reduce, {
out: { reduce: "mapReduceResults" }
}, function (err, data){
if(err)
return callback (err);
callback (null, "OK");
});
It used to work before, but just when I tried to deploy the app after testing for a while, it seems to fail in this line: team.bans.forEach(function (ban){, says team.bans is undefined, although every one of the documents has a "teams" array and a "bans" array inside of each object in it, I even double checked it by querying the database and there is no document in which those fields dont exist.
So weird. The reduce function is a bit more complex but it seems to work alright, yet the map one (unlike Reduce, its supposed to be called just once per original document, right?) throws this unexplainable error. Could anyone give me some insight?
Sample input:
{
"_id": {
"$oid": "5531a63f2a3f135c11ed14a8"
},
"matchId": 1778704162,
"region": "NA",
"platformId": "NA1",
"matchMode": "CLASSIC",
"matchType": "MATCHED_GAME",
"matchCreation": 1427864425511,
"matchDuration": 1431,
"queueType": "URF_5x5",
"mapId": 11,
"season": "SEASON2015",
"matchVersion": "5.6.0.194",
"participants": [
{
"teamId": 100,
"spell1Id": 12,
"spell2Id": 4,
"championId": 81,
"highestAchievedSeasonTier": "SILVER",
"timeline": [],
"masteries": [],
"stats": {
"winner": false,
"champLevel": 19,
"item0": 1037,
"item1": 3078,
"item2": 3117,
"item3": 3035,
"item4": 3072,
"item5": 1038,
"item6": 3340,
"kills": 7,
"doubleKills": 1,
"tripleKills": 0,
"quadraKills": 0,
"pentaKills": 0,
"unrealKills": 0,
"largestKillingSpree": 3,
"deaths": 15,
"assists": 9,
"totalDamageDealt": 103191,
"totalDamageDealtToChampions": 22148,
"totalDamageTaken": 32924,
"largestCriticalStrike": 669,
"totalHeal": 2263,
"minionsKilled": 97,
"neutralMinionsKilled": 1,
"neutralMinionsKilledTeamJungle": 1,
"neutralMinionsKilledEnemyJungle": 0,
"goldEarned": 13923,
"goldSpent": 13273,
"combatPlayerScore": 0,
"objectivePlayerScore": 0,
"totalPlayerScore": 0,
"totalScoreRank": 0,
"magicDamageDealtToChampions": 6082,
"physicalDamageDealtToChampions": 15803,
"trueDamageDealtToChampions": 263,
"visionWardsBoughtInGame": 0,
"sightWardsBoughtInGame": 0,
"magicDamageDealt": 45997,
"physicalDamageDealt": 56651,
"trueDamageDealt": 543,
"magicDamageTaken": 25249,
"physicalDamageTaken": 7490,
"trueDamageTaken": 184,
"firstBloodKill": false,
"firstBloodAssist": false,
"firstTowerKill": false,
"firstTowerAssist": false,
"firstInhibitorKill": false,
"firstInhibitorAssist": false,
"inhibitorKills": 0,
"towerKills": 4,
"wardsPlaced": 2,
"wardsKilled": 0,
"largestMultiKill": 2,
"killingSprees": 1,
"totalUnitsHealed": 1,
"totalTimeCrowdControlDealt": 98
},
"participantId": 1,
"runes": []
},
... (9 more like that)
],
"participantIdentities": [],
"teams": [
{
"teamId": 100,
"winner": false,
"firstBlood": true,
"firstTower": false,
"firstInhibitor": true,
"firstBaron": false,
"firstDragon": true,
"towerKills": 6,
"inhibitorKills": 2,
"baronKills": 0,
"dragonKills": 3,
"vilemawKills": 0,
"dominionVictoryScore": 0,
"bans": [
{
"championId": 120,
"pickTurn": 1
},
{
"championId": 37,
"pickTurn": 3
},
{
"championId": 13,
"pickTurn": 5
}
]
},
{
"teamId": 200,
"winner": true,
"firstBlood": false,
"firstTower": true,
"firstInhibitor": false,
"firstBaron": false,
"firstDragon": false,
"towerKills": 11,
"inhibitorKills": 4,
"baronKills": 0,
"dragonKills": 0,
"vilemawKills": 0,
"dominionVictoryScore": 0,
"bans": [
{
"championId": 28,
"pickTurn": 2
},
{
"championId": 38,
"pickTurn": 4
},
{
"championId": 63,
"pickTurn": 6
}
]
}
]
}
Expected output:
{
_id: { championId: Number, day: Number }
value: { banned: Number, firstBanned: Number }
}
After that, its supposed to merge with the results of a previous MapReduce operation, copying all the fields of documents with the same key (in the reduce function), but thats irrelevant now since the error happens before...
I'm very new to MongoDB, so please have mercy on me! I have a schema that looks like this:
{
"hour": 0,
"minutes": [
{
"minute": 0,
"minuteVolume": 0,
"seconds": [
{
"second": 0,
"secondVolume": 0
},
{
"second": 1,
"secondVolume": 0
}
},
{
"minute": 22,
"minuteVolume": 0,
"seconds": [
{
"second": 0,
"secondVolume": 0
},
{
"second": 1,
"secondVolume": 0
}
}],
"hourVolume": 0
}
I'm trying to update a specific "secondVolume" and "minuteVolume". I've tried the following:
collection.update({"hour": hour,
"minutes": {$elemMatch: {"minute": minute}},
"minutes.seconds": {$elemMatch: {"second": second}}},
{ $inc: {hourVolume: 1, "minutes.$.minuteVolume": 1, "minutes.$.minuteVolume.seconds.$.second": 1}
},
{upsert:false,safe:true},
function(err,data){
if (err){
console.log(err);
}
else
{
console.log(data);
}
}
);
but I'm clearly doing something wrong. If I remove the $elemMatch for "second" and only try to update the "minuteVolume", it works just groovy. This leads me to believe that I'm doing something wrong with the positional operators or that my query isn't unwinding the document properly.
Is this even possible with a single query in MongoDB? I'm using mongodb driver version 1.4.19.
Thanks a lot in advance!
It looks like you can me and the 240 people who have voted for this feature.
https://jira.mongodb.org/browse/SERVER-831
If you know the position of the elements (possibly by querying the document first) you can update by using positional operators instead of by using $elemMatch.
{ $inc: {hourVolume: 1, "minutes.0.minuteVolume": 1, "minutes.0.minuteVolume.seconds.2.second": 1 }
I've had to redo several schemas to prevent multi-nesting and therefore allow for a one-shot update.