Select only documents with id value not in the collection - mongodb

I have a collection ft with a number of records in it. However,i want to exclude certain ids that i have in a comma delimited list.
I am trying to do the following
var ids = [ "RQcWthREHBTfkybMy", "jiPrzQQWxbN5a8pEC", "5oFxC68WEggYzY7ah" ]
db.collection.find( { _id: { $ne: ids } } )
but i can only manage to exclude RQcWthREHBTfkybMy which is the first id in my list.

The $ne query operator behavior when the specified value is array is quite different from the the $eq operator. To check if a field value is not in the specified array you need to use the $nin query operator.
var ids = [ "RQcWthREHBTfkybMy", "jiPrzQQWxbN5a8pEC", "5oFxC68WEggYzY7‌​ah" ]
db.collection.find( { "_id": { "$nin": ids } } )

Related

How to query certain elements of an array of objects? (mongodb)

say I have a mongo DB collection with records as follows:
{
email: "person1#gmail.com",
plans: [
{planName: "plan1", dataValue = 100},
{planName: "plan2", dataValue = 50}
]
},
{
email: "person2#gmail.com",
plans: [
{planName: "plan3", dataValue = 25},
{planName: "plan4", dataValue = 12.5}
]
}
and I want to query such that only the dataValue returns where the email is "person1#gmail.com" and the planName is "plan1". How would I approach this?
You can accomplish this using the Aggregation Pipeline.
The pipeline may look like this:
db.collection.aggregate([
{ $match: { "email" :"person1#gmail.com", "plans.planName": "plan1" }},
{ $unwind: "$plans" },
{ $match: { "plans.planName": "plan1" }},
{ $project: { "_id": 0, "dataValue": "$plans.dataValue" }}
])
The first $match stage will retrieve documents where the email field is equal to person1#gmail.com and any of the elements in the plans array has a planName equal to plan1.
The second $unwind stage will output one document per element in the plans array. The plans field will now be an object containing a single plan object.
In the third $match stage, the unwound documents are further matched against to only include documents with a plans.planName of plan1. Finally, the $project stage excludes the _id field and projects a single dataValue field with a value of plans.dataValue.
Note that with this approach, if the email field is not unique you may have multiple documents consist with just a dataValue field.

How to query nested arrays in mongoDB to find documents with elements that don't exist

I'm trying to make an aggregation query to find all documents that do not contain a certain element. It needs to be an aggregation because I want to be able to edit the returned documents. Eg. I only want to return some fields and I also want to be able to do a group on eg. the "producer" element.
I already tried practically all I can think of. I tried unwinding the arrays, but then I created even more documents where the element packagingInformation was mission than originally. I tried using $ne, $eq, $gt, $lte,.. to find the documents needed,... but they always return all documents because of the nested array structure.
$ArrayToObject didn't do the trick either for me.
I'm clueless on how to achieve this. The tripple nested array structure beats my imagination.
The only thing that returns me the wanted result is the following query:
db.product.find({
"json.productData.productInformation.details.packagingInformation": { $exists: false }
})
But this doesn't suffice since it's not an aggregate, thus it doens't allow me to continue to do queries with the results. And the $exists doesn't work in aggregates.
This is the JSON structure which I'm struggling with (dummy data).
{
_id: 5ckflsmdk543klmf543klmtrkmgdfm,
productNumber: 001,
json: {
productData: {
productNumber: 001,
producer: coca-cola,
productInformation: [
{
trackingInformation: {
lastUpdate: 01-01-12,
creationDate: 01-01-11
},
details: [
packagingInformation: [
quantity: 5,
size: 20cm
],
productType: drinks,
otherMeaningLessInformation: whatever,
andEvenMoreInformationInArrays: [
andTheInformationGoesOn: wow,
andOn: nastyArrayStructures
]
]
]
}
}
}
}
The wanted result would be to return all the documents that do not contain the packagingInformation array or the packagingInformation.quantity element.
or even better, to return all documents but with an extra field:
containsPackagingInformation: true/false. With false being the result of all documents that do not contain packagingInformation or packagingInformation.quantity.
$exists DOES WORK in a aggregation.
$exists works the same way it works in .find
you can form a query like:
db.collection.aggregate({ $match: {
$or: [
{
"json.productData.productInformation.details.packagingInformation.quantity": {
$exists: false
}
},
{
"json.productData.productInformation.details.packagingInformation": {
$exists: false
}
}
] } })
Try this query here with dummy data

Mongodb - remove or replace all array elements

How can i replace all elements from a mongodb array element. As in below example, my requirement is to remove both object from skills array and add new elements in it.
{
"_id": "uniqueid",
"skills": [
{ "skill": "dancer" },
{ "skill": "singer" }
]
}
I need to replace all element of skills array field. How this can be achieved using mongodb java driver, or other query types?
You just need to use $set operator $set to set skills to a new value which will be an array of the new element you want to replace with.
db.collectionName.update(
{ _id: 'uniqueid' },
{ $set:
{
skills: [{'new elements'}]
}
}
)
if you want to remove all elements set the skills to an empty array {skills: []}
if you want to remove a certain elements based on a value use $pull operator $pull

MongoDB distinct- returns only matched array elements

I was trying to fetch distinct tags from array for auto-complete module. The collection format is:
{
tags:["apple","mango","apple-pie"]
},
{
tags: ["man","lemon","lemon-lite"]
}
Now, I am interested in getting distinct tags, with prefix q.
The query that I triggered is:
db.portfolio.distinct("tags",{"tags":/app/});
However, this query returned entire array:
["apple","mango","apple-pie"].
My requirement is: ["apple", "apple-pie"].
How can I modify my query to get desired result?
You can do this with aggregation.
You $unwind the tags array.
You $match those tags you are looking for according to the regular expression given.
You $group the tags into a set using $addToSet.
The code looks something like this:
> db.portfolio.aggregate([
{ "$unwind": "$tags" },
{ "$match": { "tags": /app/ }},
{ "$group":
{
"_id": null,
"tags": { "$addToSet": "$tags" }
}
}
]);
{ "_id" : null, "tags" : [ "apple-pie", "apple" ] }
Not possible with distinct because query will return documents containing matching tags(/app/) which mean there will be non matching tags as well. distinct gets a distinct set from all these tags.
So you will have to filter the returning array again( using regex /app/)

usage for MongoDB sort in array

I would like to ranked in descending order a list of documents in array names via their number value.
Here's the structure part of my collection :
_id: ObjectId("W")
var1: "X",
var2: "Y",
var3: "Z",
comments: {
names: [
{
number: 1;
},
{
number: 3;
},
{
number: 2;
}
],
field: Y;
}
but all my request with db.collection.find().sort( { "comments.names.number": -1 } ) doesn't work.
the desired output sort is :
{ "_id" : ObjectId("W"), "var1" : "X", "var3" : "Z", "comments" : { [ { "number" : 3 }, { "number" : 2 },{ "number" : 1 } ], "field": "Y" } }
Can you help me?
You need to aggregate the result, as below:
Unwind the names array.
Sort the records based on comments.names.number in descending
order.
Group the records based on the _id field.
project the required structure.
Code:
db.collection.aggregate([
{$unwind:"$comments.names"},
{$sort:{"comments.names.number":-1}},
{$group:{"_id":"$_id",
"var1":{$first:"$var1"},
"var2":{$first:"$var2"},
"var3":{$first:"$var3"},
"field":{$first:"$comments.field"},
"names":{$push:"$comments.names"}}},
{$project:{"comments":{"names":"$names","field":"$field"},"var1":1,
"var2":1,"var3":1}}
],{"allowDiskUse":true})
If your collection is large, you might want to add a $match criteria in the beginning of the aggregation pipeline to filter records or use (allowDiskUse:true), to facilitate sorting large number of records.
db.collection.aggregate([
{$match:{"_id":someId}},
{$unwind:"$comments.names"},
{$sort:{"comments.names.number":-1}},
{$group:{"_id":"$_id",
"var1":{$first:"$var1"},
"var2":{$first:"$var2"},
"var3":{$first:"$var3"},
"field":{$first:"$comments.field"},
"names":{$push:"$comments.names"}}},
{$project:{"comments":{"names":"$names","field":"$field"},"var1":1,
"var2":1,"var3":1}}
])
What The below query does:
db.collection.find().sort( { "comments.names.number": -1 } )
is to find all the documents, then sort those documents based on the number field in descending order. What this actually does is for each document get the comments.names.number field value which is the largest, for each document. And then sort the parent documents based on this number. It doesn't manipulate the names array inside each parent document.
You need update document for sort an array.
db.collection.update(
{ _id: 1 },
{
$push: {
comments.names: {
$each: [ ],
$sort: { number: -1 }
}
}
}
)
check documentation here:
http://docs.mongodb.org/manual/reference/operator/update/sort/#use-sort-with-other-push-modifiers
MongoDB queries sort the result documents based on the collection of fields specified in the sort. They do not sort arrays within a document. If you want the array sorted, you need to sort it yourself after you retrieve the document, or store the array in sorted order. See this old SO answer from Stennie.