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 }
Related
I'm trying to get all the values(which are arrays) of the "coordinate" type in my data like that:
[
["51.50064317423898","-0.09372711181640626"],
["51.48465408363687","-0.13149261474609378"]
]
I tried db.collections("mydb").distinct("coordinate") but i get:
[
'-0.09372711181640626',
'-0.13149261474609378',
'51.48465408363687',
'51.50064317423898'
]
Does anyone have an idea how i can just have all my arrays like i want and not ordered in one array?
"mydb" looks like this:
{
"name":"dfbfdbf",
"coordinate":["51.50064317423898","-0.09372711181640626"],
"rating":"8",
"description":"geojzglijsen"
},
{
"name":"qzfgs",
"coordinate":["51.48465408363687","-0.13149261474609378"],
"rating":"5",
"description":"femkndsmnk"
}
Thank you!
If I've understood correctly you can try this aggregate query:
The point is $group by null to get all values and use $addToSet which prevents the duplicates values.
db.collection.aggregate([
{
"$group": {
"_id": null,
"coordinate": {
"$addToSet": "$coordinate"
}
}
},
{
"$project": {
"_id": 0
}
}
])
Example here where I've duplicated one object to see how the repeated value is not displayed.
If you need to fetch distinct coordinates from your collection:
mongos> db.a.find()
{ "_id" : ObjectId("619ea12e032deead586f3f91"), "name" : "dfbfdbf", "coordinate" : [ "51.50064317423898", "-0.09372711181640626" ] }
{ "_id" : ObjectId("619ea138032deead586f3f92"), "name" : "a", "coordinate" : [ "51.50064317423898", "-0.09372711181640626" ] }
{ "_id" : ObjectId("619ea14c032deead586f3f93"), "name" : "a", "coordinate" : [ "51.50064317423898", "-0.19372711181640626" ] }
{ "_id" : ObjectId("619ea157032deead586f3f94"), "name" : "a", "coordinate" : [ "51.50064317423898", "-0.09372711181640626" ] }
{ "_id" : ObjectId("619ea15b032deead586f3f95"), "name" : "a", "coordinate" : [ "52.50064317423898", "-0.09372711181640626" ] }
{ "_id" : ObjectId("619ea160032deead586f3f96"), "name" : "a", "coordinate" : [ "52.50064317423898", "-0.09372711181640626" ] }
mongos> db.a.aggregate([
{ $addFields:{coordinates:{$reduce:{ input: {$slice:["$coordinate",1,{$size:"$coordinate"} ]},initialValue:{$arrayElemAt:["$coordinate",0]},in:{$concat:["$$value",";","$$this" ]} }} }} ,
{ $group:{_id:"$coordinates" , cnt:{$sum:1}}} ,
{ $project : { coordinate : { $split: ["$_id", ";"] } ,_id:0}}
])
{ "coordinate" : [ "51.50064317423898", "-0.19372711181640626" ] }
{ "coordinate" : [ "51.50064317423898", "-0.09372711181640626" ] }
{ "coordinate" : [ "52.50064317423898", "-0.09372711181640626" ] }
mongos>
Example:
here
explained:
Remove duplicate coordinates from collection
create new field coordinates where you join the coordinates in single string
group the coordinates to remove duplicates
split the coordinates to the original values.
This solution has no limitation of distinct coordinates array summary size of 16MB as well ...
In a Typesctipt code, I would like to use a varible value in an aggregation pipeline in MongoDB; the problem is that the "keyToCheck" field is a variable that is set by the Typescript code and, therefore, can change based by many conditions.
Is there a way to expand the variable "keyToCheck"?
I have tried $$keyToCheck, $keyToCheck with no result (compilation errors).
Thanks.
...
const pipeline = [
{
$match: {
[this.countryOriginFieldName!]: {
$in: members
},
**keyToCheck**: {
$nin: dictionaryNotAbsoluteFieldList
}
}
},
...
UPDATE: try with this example:
var keyToCheck = "indicator";
var queryMatch = {"`$${keyToCheck}`": "US$millions"}
printjson(queryMatch);
db.getCollection("temp_collection").aggregate([
{
$match: queryMatch
},
{$project: {indicator: 1, value: 1}}
]
);
db.getCollection("temp_collection").insertMany([
{
"indicator" : "US$millions",
"value" : 1.0
},
{
"indicator" : "US$millions",
"value" : 2.0
},
{
"indicator" : "EUROmillions",
"value" : 3
}
]);
Desired output:
{
"indicator" : "US$millions",
"value" : 1.0
}
{
"indicator" : "US$millions",
"value" : 2.0
}
Query
the [keyToCheck] is to take the value of the variable, its not an array
here its assumed that you want to project also the keyToCheck, and not always project the indicator
var keyToCheck = "indicator";
db.getCollection("temp_collection").aggregate([
{
$match: {[keyToCheck]: "US$millions"}
},
{$project: {[keyToCheck]: 1, value: 1}}
]
);
This will work, key will be just a string,and in project also just a string.
You dont need $ or $$ with this query.
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 :)
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? :)
I have 2 mongodb collections, stu_creds and stu_profile. I first want to retrieve all the student records from stu_creds where stu_pref_contact is the email and then for those stu_ids I want to retrieve the complete profile from stu_profile. The problem is, the first query returns an array of JSON documents, with each document holding one field, the stu_id. Here is my query and the result:
db.stu_creds.find({"stu_pref_contact" : "email"}, {'_id' : 1})
Result:
[{ "_id" : ObjectId("51927cc93080baac04000001") },
{ "_id" : ObjectId("51927d7b3080baac04000002") },
{ "_id" : ObjectId("519bb011c5c5035b2a000002") },
{ "_id" : ObjectId("519ce3d09f047a192b000010") },
{ "_id" : ObjectId("519e6dc0f919cfdc66000003") },
{ "_id" : ObjectId("51b39be0c74f0e3d23000012") },
{ "_id" : ObjectId("51b39ca9c74f0e3d23000014") },
{ "_id" : ObjectId("51b39cb7c74f0e3d23000016") },
{ "_id" : ObjectId("51b39e87c74f0e3d23000018") },
{ "_id" : ObjectId("51b39f2fc74f0e3d2300001a") },
{ "_id" : ObjectId("51b39f47c74f0e3d2300001c") },
{ "_id" : ObjectId("518d454deb1e3a525e000009") },
{ "_id" : ObjectId("51bc8381dd10286e5b000002") },
{ "_id" : ObjectId("51bc83f7dd10286e5b000004") },
{ "_id" : ObjectId("51bc85cbdd10286e5b000006") },
{ "_id" : ObjectId("51bc8630dd10286e5b000008") },
{ "_id" : ObjectId("51bc8991dd10286e5b00000a") },
{ "_id" : ObjectId("51bc8a43dd10286e5b00000c") },
{ "_id" : ObjectId("51bc8a7ddd10286e5b00000e") },
{ "_id" : ObjectId("51bc8acadd10286e5b000010") }]
The thing is, I don't think I can use the above array as part of an $in clause for my second query to retrieve the student profiles. I have to walk through the array and and create a new array which is just an array of object ids rather than an array of JSON docs.
Is there an easier way to do this?
Use Array.map (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). This allows you to perform a transform on each element of the array, returning you a new array of the transformed items.
var arrayOfIds = result.map(function(item){ return item._id; });
Array.map was introduced in ECMAScript 5. If you're using node.js, a modern browser, or an Array polyfill, it should be available to use.
Ummm, am I missing something or is all you want the following:
var results = [];
for(var i = 0; i < yourArray.length; i++) {
results.push(yourArray[i]._id);
}
You could use $or:
db.stu_profile.find({ $or : results }) // `results` is your list of ObjectId's
But it's considerably slower than $in, so I would suggest using one of the other answers ;)