Confirm $addToSet adds an element - node.js

I have a function adding a bunch of data into db through $addToSet, and I require a confirmation if the data has been added or not. Since $addToSet does not add duplicates, I want to know if a duplicate has not been added (show an error to the user) or if a db entry has been added (show confirmation to user).
I basically need a callback for the $addToSet operation. Couldnt find it in the docs. New to mongodb. Would appreciate help.
_notifications.update(
{'username': data.username},
{ $addToSet: pushNotification }, function(err, docs){
console.log(docs);
if (docs == 0){
co_notifications.insert(
{'username': data.username, 'notifications': insertNotification}, function(er, doc){
});
}
},
{ upsert: true }
);

I may be missing something but the only thing I can really see is in the result of the new Batch operations API.
var mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient;
MongoClient.connect("mongodb://localhost/test",function(err,db) {
var col = db.collection("mytest");
var batch = col.initializeOrderedBulkOp();
batch.find({ "user": "me" }).upsert().updateOne({ "$addToSet": { "list": 5 } });
batch.execute(function(err,result) {
console.log( JSON.stringify( result, undefined, 4 ) );
});
});
On that sample listing the first time you execute the contents of "result" will dump like this:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"nInserted": 0,
"nUpserted": 1,
"nMatched": 0,
"nModified": 0,
"nRemoved": 0,
"upserted": [
{
"index": 0,
"_id": "5397ae995f04804cbeb7c663"
}
]
}
The notable keys there being "nUpserted" and the "upserted" array for each document that was created. It is a batch operation afterall even though we are doing it once.
On the second execution where it should find the existing document and also match the set member you would get this:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"nInserted": 0,
"nUpserted": 0,
"nMatched": 1,
"nModified": 0,
"nRemoved": 0,
"upserted": []
}
That shows that while the document was matched nothing was actually modified as the set member was the same. But if you change the value of what is applied in the $addToSet operation to something that doesn't exist then the response would be this:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"nInserted": 0,
"nUpserted": 0,
"nMatched": 1,
"nModified": 1,
"nRemoved": 0,
"upserted": []
}
This shows both the "nMatched" and "nModified" values indicating the document was actually updated by the $addToSet operation.
So that may be a possible approach

Related

How to update every document in collection based off another collection with Mongoose

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.

how to retrieve a document with some parameters excluded in the nested array in mongo?

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

insert array using insert many function of mongoose

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"
}]

MongoDB MapReduce weird bug

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...

MongoDB - Updating multiple levels of subdocuments with multiple $elemMatch operators in node.js

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.

Resources