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 :)
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'm trying to sort my snapshots by using orderByChild but this thing is not working.
FIREBASE RULES :
"rules": {
"community": {
"users": {
".read": true,
"$uid": {
".read": true,
".write": "$uid === auth.uid",
".indexOn": ["pseudo", "pseudoLower", "pseudoInverseLower", "films"]
}
}
}
}
DATA :
"community" : {
"users" : {
"Ab" : {
"films" : 200,
"filters" : 2,
"id" : "Ab",
"pseudoBase" : "AB",
"pseudoInverseLower" : "zy",
"pseudoLower" : "ab"
},
"Bc" : {
"films" : 692,
"filters" : 4,
"id" : "Bc",
"pseudoBase" : "King",
"pseudoInverseLower" : "prmt",
"pseudoLower" : "king"
},
"Ce" : {
"films" : 100,
"filters" : 5,
"id" : "a",
"pseudoBase" : "A",
"pseudoInverseLower" : "z",
"pseudoLower" : "a"
}
}
}
JS :
db.ref('community/users').orderByChild('films').once('value', snap => {})
In the user data you'll retrieve his pseudo (and the inverse), his films length and filters length.
I tried orderByChild('pseudoLower'), .orderByChild('films') and .orderByChild('pseudoInverseLower') but nothing changed.
I'm really stuck at this point... Maybe I forgot something?
You need to convert the resultant snapshot into an array of children – this can be done using the snapshot forEach method and this will iterate the children in order of the child key provided in the query. The users will lose the order they were received in if you print the snapshot value.
async function getCommunityUsers(filter) {
const usersRef = admin.database().ref('community/users')
const snapshot = await usersRef.orderByChild(filter).once('value')
let users = []
snapshot.forEach(child => {
users.push({
key: child.key,
...child.val()
})
return false
})
return users
}
Hello I have a posts collection in mongodb where there's an authors field and when I run the following command:
db.posts.aggregate( [ {$project:{ size: {$size: {$ifNull:["$authors", []] }}}} ] )
I get a result like that:
{ "_id" : ObjectId("58c917fe48ad625ee8f49714"), "size" : 30 }
{ "_id" : ObjectId("58c91b83895efc5f0f67ba1a"), "size" : 0 }
{ "_id" : ObjectId("58c91cfd2971c05f310fccb8"), "size" : 30 }
{ "_id" : ObjectId("58c91eb7a826965f85571656"), "size" : 30 }
{ "_id" : ObjectId("58c921a1cb2bc85fa77e593a"), "size" : 30 }
How can I count the number of times when size is not equal to 0?
So in that case the result would be 4.
I tried "db.posts.aggregate( [ {$project:{ size: {$size: {$not:{"$authors": 0} }}}} ] )
" with no success...
You want to use $match and $count aggregation methods, something like the below. See more MongoDB Aggregate $count
db.posts.aggregate(
[ {
$match:{ size: {$gt: 0}}
}, {
$count:'total'
} ] )
This should return something like:
{ "total" : 4 }
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.
After performing some aggregation magic, I have arrived at this data:
{ "_id" : "5700edfe03fcdb000347bebb", "size" : 3, "count" : 2 }
{ "_id" : "5700edfe03fcdb000347bebf", "size" : 2, "count" : 2 }
Now, I want to eliminate all the entries where size is equal to count.
So I ran this aggregation instruction:
match3 = { "$match" : { "size" : { "$ne" : "count"} } }
But it doesn't eliminate anything and returns the two lines as it is.
I want the result to be just this one line as it is the only one where size is not equal to count:
{ "_id" : "5700edfe03fcdb000347bebb", "size" : 3, "count" : 2 }
You need to add a $redact stage to your aggregation pipeline:
{ "$redact": {
"$cond": [
{ "$eq": [ "$size", "$count" ] },
"$$PRUNE",
"$$KEEP"
]
}}
You can use the $where operator for this
db.collection.find({ $where: "this.size != this.count" })
db.collection.remove({ $where: "this.size != this.count" })
UPDATE:
After I got downvoted I decided to compare the 2 solutions.
Both use a COLLSCAN and both return the same results.
So please enlighten me what is so wrong about my solution? :)