MongoDB shell, $pop works weirdly - javascript

I'm learning MongoDB, and I decided to try a little exercise with the $pop :
MongoDB Enterprise > db.produits.insert({compteur: 100001, tab:['a','b','c']})
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise > db.produits.find({compteur: 100001});
{ "_id" : ObjectId("57c011106d76da1c1e34edd2"), "compteur" : 100001, "tab" : [ "a", "b", "c" ] }
MongoDB Enterprise > db.produits.update({compteur: 100001}, {$push: {tab: 'd'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
MongoDB Enterprise > db.produits.find({compteur: 100001});
{ "_id" : ObjectId("57c011106d76da1c1e34edd2"), "compteur" : 100001, "tab" : [ "a", "b", "c", "d" ] }
MongoDB Enterprise > db.produits.update({compteur: 100001}, {$pop:{tab:1}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
MongoDB Enterprise > db.produits.find({compteur: 100001});
{ "_id" : ObjectId("57c011106d76da1c1e34edd2"), "compteur" : 100001, "tab" : [ "a", "b", "c" ] }
MongoDB Enterprise > db.produits.update({compteur: 100001}, {$push:{tab:['d', 'e', 'f', 'g']}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
MongoDB Enterprise > db.produits.find({compteur: 100001});
{ "_id" : ObjectId("57c011106d76da1c1e34edd2"), "compteur" : 100001, "tab" : [ "a", "b", "c", [ "d", "e", "f", "g" ] ] }
MongoDB Enterprise > db.produits.update({compteur: 100001}, {$pop:{tab:3}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
MongoDB Enterprise > db.produits.find({compteur: 100001});
{ "_id" : ObjectId("57c011106d76da1c1e34edd2"), "compteur" : 100001, "tab" : [ "a", "b", "c" ] }
I don't understand the logic :
The last pop deleted the array in the array, but why ?
I asked to pop 3, I was thinking it could :
1 - Pop the 3 last entries in the tab inside the tab (So "e", "f", and "g")
2 - Pop the table as a single element, and then pop the 2 element before (So "b" and "c")
Here I am so, I don't understand what happened :/

I don't think it's a bug as that's the intended behaviour of the $pop operator. It removes the first or last element of an array, the array in this case is a stack and doesn't ever remove more than 1 element. So 3 vs. 1 as a value is treated the same (thanks to #JohnnyHK for this quote).
Since the last item in the tab field is an array, the operation
db.produits.update({compteur: 100001}, {$pop:{tab:3}});
correctly pops the last element (which is the array).
The operation you're looking for is probably
db.produits.update({compteur: 100001}, {$pop:{"tab.3":-1}});
which pops the first element in the embedded array "d", or
db.produits.update({compteur: 100001}, {$pop:{"tab.3":1}});
to pop the last "g".
I think maybe you are looking for the $slice operator here to "pop" multiple elements.

Related

mongodb collection uuid how to update?

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});

Accumulate scores

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

How to increment existing value in MongoDB

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 :)

MongoDB - Find elements, where field is equal to at least one value at array

I have "reverse" problem to classic "find value(s) in array".
I get array of ids and I want to find elements, which has field with value in this array.
Example :
I have this in MyCollection
{a: 10}
{a: 7}
{a: 6}
{a: 15}
And I want to do query like this
MyCollection.find({a: [6,15])
Which would return me
[
{a: 6},
{a: 15}
]
Please try to use $in
> db.testdata.find({a: {$in: [6, 15]}})
With data
> db.testdata.find()
{ "_id" : ObjectId("56e800e2abc8519548297bc3"), "a" : 10 }
{ "_id" : ObjectId("56e800e5abc8519548297bc4"), "a" : 6 }
{ "_id" : ObjectId("56e800eaabc8519548297bc5"), "a" : 15 }
And test code
> db.testdata.find({a: {$in: [6, 15]}})
{ "_id" : ObjectId("56e800e5abc8519548297bc4"), "a" : 6 }
{ "_id" : ObjectId("56e800eaabc8519548297bc5"), "a" : 15 }
You can $gte - greater and lt - less than
db.collection.find({ "a" : { $gte: 6, $lte: 15} } );

MongoDB Limit fields and slice projection together

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

Categories