I have a collection in mongoDB with documents like:
{
"_id" : ObjectId("some_id"),
"name" : "name",
"field1" : 123,
"field2" : 234,
"arr" : [
{
"a_num" : 3,
"arr" : [
"abc",
"def"
],
},
{
"a_num" : 36,
"arr" : [
"hi"
],
},
{
"a_num" : 34,
"arr" : [
"abc"
],
}
]
}
While I'm using find()
I don't want to get the arr elements where arr has only 1 element, that its value is "abc".
E.g, for the above document, I'd like to get:
{
"_id" : ObjectId("some_id"),
"name" : "name",
"field1" : 123,
"field2" : 234,
"arr" : [
{
"a_num" : 3,
"arr" : [
"abc",
"def"
],
},
{
"a_num" : 36,
"arr" : [
"hi"
],
},
]
}
Any idea how?
Thanks!
You'll need to use the aggregation framework with $filter, like so:
db.collection.aggregate([
{
$addFields: {
arr: {
$filter: {
input: "$arr",
cond: {
$ne: [
"$$this.arr",
[
"abc"
]
]
}
}
}
}
}
])
I have the following collection:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
{ "_id" : 5, "tags" : [ "homes", "maps", "bones" ] }
{ "_id" : 6, "tags" : [ "xxx", "yyy", "zzz" ] }
I would like to return all documents where "tags" matches documents with exactly the same array elements.
So thus, if I were to query for tags == ["school", "home"] or tags == ["home", "school"], document w/ _id=1 would be returned
I am doing the following:
db.test.find({tags: {$in: ['school', 'home']}}) or
db.test.find({tags: {$in: ['home', 'school']}})
and the following are returned:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
How may I achieve only item w/ _id=1 be returned?
Maybe something like this:
Option 1:
db.collection.find({
$and: [
{
tags: "school"
},
{
tags: "home"
},
{
tags: {
$size: 2
}
}
]
})
Explained:
Match if school & home are in the tags array and if array size is 2.
Playground
Option 2:
db.collection.find({
$or: [
{
tags: [
"school",
"home"
]
},
{
tags: [
"home",
"school"
]
}
]
})
Explained:
Match the two possible array options
Playground2
i am new to MongoDB and I have documents as below
{ "_id" : ObjectId("604b7d62b19a72a2b89028e6"), "name" : "ram", "tags" : [ "mobile", "iphone", "india" ] }
{"_id" : ObjectId("604b7d83b19a72a2b89028e7"), "name" : "shyam", "tags" : [ "mobile", "iphone", "india" ] }
{ "_id" : ObjectId("604b7d9bb19a72a2b89028e8"), "name" : "ravi", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "windows", "usa" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "tech", "apple", "microsoft" ] }
How to write query so that if i query for following tags ["mobile", "android", "12", "pro"] i would get following result
{ "_id" : ObjectId("604b7d9bb19a72a2b89028e8"), "name" : "ravi", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7d62b19a72a2b89028e6"), "name" : "ram", "tags" : [ "mobile", "iphone", "india" ] }
{ "_id" : ObjectId("604b7d83b19a72a2b89028e7"), "name" : "shyam", "tags" : [ "mobile", "iphone", "india" ] }
Demo - https://mongoplayground.net/p/EMW8xgV1yrU
Use $in
The $in operator selects the documents where the value of a field equals any value in the specified array. To specify an $in expression, use the following prototype:
db.collection.find({
tags: { $in: [ "mobile", "android", "12", "pro" ] }
})
I am using express to query my mongodb database using the native driver (not Mongoose.)
I am trying to do some data clean up after a MongoDB response. I don't mind if this could be achieved with MongoDB's aggregation query or some variation of it, for completeness the current query I'm using is: collection.find({'make.name': req.params.make}, {'model.name': 1, 'submodel.body': 1, '_id': 0}).toArray();
I have a response from mongodb:
[
{
"model" : {
"name" : "3 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "3 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "3 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Convertible"
}
},
{
"model" : {
"name" : "2 Series"
},
"submodel" : {
"body" : "Coupe"
}
}
]
which I would like to simplify to this:
[
"model" : {
"name": "2 Series"
}
"submodel" : {
"body": ["Convertible", "Coupe"]
}
"model" : {
"name": "3 Series"
}
"submodel" : {
"body": ["Convertible", "Coupe"]
}
]
New output:
{ "_id" : "M3", "submodel" : [ "Sedan" ] }
{ "_id" : "X5 eDrive", "submodel" : [ "SUV" ] }
{ "_id" : "X5 M", "submodel" : [ "SUV" ] }
{ "_id" : "M4 GTS", "submodel" : [ "Coupe" ] }
{ "_id" : "ActiveHybrid 5", "submodel" : [ "Sedan" ] }
{ "_id" : "X5", "submodel" : [ "SUV" ] }
{ "_id" : "X6 M", "submodel" : [ "SUV" ] }
{ "_id" : "i8", "submodel" : [ "Coupe" ] }
{ "_id" : "X4", "submodel" : [ "SUV" ] }
{ "_id" : "5 Series Gran Turismo", "submodel" : [ "Hatchback" ] }
{ "_id" : "M4", "submodel" : [ "Coupe", "Convertible" ] }
{ "_id" : "5 Series", "submodel" : [ "Sedan" ] }
{ "_id" : "M6 Gran Coupe", "submodel" : [ "Sedan" ] }
{ "_id" : "X1", "submodel" : [ "SUV" ] }
{ "_id" : "3 Series eDrive", "submodel" : [ "Sedan" ] }
{ "_id" : "2 Series", "submodel" : [ "Coupe", "Convertible" ] }
{ "_id" : "6 Series Gran Coupe", "submodel" : [ "Sedan" ] }
{ "_id" : "3 Series", "submodel" : [ "Wagon", "Sedan" ] }
{ "_id" : "Z4", "submodel" : [ "Convertible" ] }
{ "_id" : "6 Series", "submodel" : [ "Convertible", "Coupe" ] }
new output:
{
"_id": "2 Series",
"submodel": [
"Coupe",
"Convertible"
]
},
{
"_id": "3 Series",
"submodel": [
"Wagon",
"Sedan"
]
},
{
"_id": "3 Series Gran Turismo",
"submodel": [
"Hatchback"
]
},
{
"_id": "3 Series eDrive",
"submodel": [
"Sedan"
]
},
{
"_id": "4 Series",
"submodel": [
"Coupe",
"Convertible"
]
},
As you can see, model.name is a unique property, and "submodel.body" is now an array of unique body types.
How can I convert my array of non-unique models, to an array of unique models?
Current Query:
router.get('/test/:make', (req, res) => {
var collection = db.get().collection('styles');
collection.aggregate({
$match: {
$or: [{
"make.niceName": req.params.make
},
{
"make.name": req.params.make
}
]
}
}, {
$group: {
_id: "$model.name",
"submodels": {
$addToSet: "$submodel.body"
}
}
}, {
$sort: {
_id: 1
}
}, {
$project: {
models: "$_id",
submodel: 1,
_id: 0
}
}).toArray((err, docs) => {
res.send(docs)
})
You can try below aggregation pipeline. $addToSet to get distinct submodel in each model group.
collection.aggregate({
$match: {
"make.name": req.params.make
}
}, {
$group: {
_id: "$model.name",
submodel: {
$addToSet: "$submodel.body"
}
}
}, {
$sort: {
_id: 1
}
}, {
$project: {
models: "$_id",
submodel: 1,
_id: 0
}
})
I have a query like below.Obviously the better index is "platform_1_keyuserAccountID_1_weiboAccountID_1_postTime_1",but mongodb choose "weiboAccountID_1",am i make something wrong?
db.inbox_weibo.find({platform: "sina", keyuserAccountID:"1665337047", weiboAccountID: "2271338624"}).explain(true);
{
"cursor" : "BtreeCursor weiboAccountID_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 24,
"nscannedAllPlans" : 634425,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 1,
"nChunkSkips" : 0,
"millis" : 2912,
"indexBounds" : {
"weiboAccountID" : [
[
"2271338624",
"2271338624"
]
]
},
"allPlans" : [
{
"cursor" : "BtreeCursor weiboAccountID_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"weiboAccountID" : [
[
"2271338624",
"2271338624"
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_dealed_1_operatorID_1_weiboAccountID_1_postTIme_-1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 62,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"operatorID" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"weiboAccountID" : [
[
"2271338624",
"2271338624"
]
],
"postTIme" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_weiboAccountID_1_postTime_-1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"weiboAccountID" : [
[
"2271338624",
"2271338624"
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_keyuserAccountID_dealed_postTime_weiboAccountID",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 634331,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"weiboAccountID" : [
[
"2271338624",
"2271338624"
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_mid_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"mid" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_dealerID_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealerID" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor distinctAccountAgg",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"operatorID" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor fansCountUndealed",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"fromType" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"fansCount" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"usePicture" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor retweetCountUndealed",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"fromType" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"sourceRetweetCount" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"usePicture" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor interactUndealed",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"fromType" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"userInteractionCount" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"usePicture" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_dealed_1_dealTime_-1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"dealTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_dealerID_1_postTime_-1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealerID" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor platform_1_keyuserAccountID_1_postTime_-1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"platform" : [
[
"sina",
"sina"
]
],
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"postTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor keyuserAccountID_dealed_createTime_-1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 2,
"nscanned" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"keyuserAccountID" : [
[
"1665337047",
"1665337047"
]
],
"dealed" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"createTime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
}
I don't think the other index is "better". It seems that both indexes (the one you would suggest and the one mongodb uses) return the queried object with "nscanned:1", so they are equally perfect for this query. I say that since "weiboAccountID" in your test dataset defines exactly the one record you are looking for, there is no need for other indexes in this case - mongodb will choose the first good fit. Try adding more records with this same exact weiboAccountID (if duplicated Ids are at all valid in your dataset) and re-run the query, see how it changes the execution.