Mongodb: Combine $in and $nin - mongodb

In my collection posts I've documents like this
[{
_id : ObjectId("post-object-id"),
title : 'Post #1',
category_id : ObjectId("category-object-id")
}]
I need to make some queries where I those a range of posts based on their category_id (can be multiple ids) but exclude some of them.
I've tried with the query (in shell):
db.posts.find({$and: [
{_id: { $nin : ['ObjectId("post-object-id")']}},
{category_id : { $in : ['ObjectId("category-object-id")']}}
]})
I returns 0 if count().
However, if I change the category_id attribute and remove the $in and just include one ID it work, like this:
db.posts.find({$and: [
{_id: { $nin : ['ObjectId("58a1af81613119002d42ef06")']}},
{category_id : ObjectId("58761634bfb31efd5ce6e88d")}
]})
but this solution only enables me to find by one category.
How would I got about combining $in and $nin with objectId's in the same manner as above?

This will work, just remove single quotes around ObjectId
db.posts.find({$and: [
{_id: { $nin : [ObjectId("post-object-id")]}},
{category_id : { $in : [ObjectId("category-object-id")]}}
]})
You should not put single quotes around ObjectId, it make them strings

Related

MongoDB: find document whose subdocument contains a given value

Given is a Document like the following
{
"type" : "sometype",
"title" : "sometitle",
"references":{
"1": "someref",
"2": "otherref",
"3": ""
}
}
How can I find all documents which have the reference someref set in the subdocument references?
A simple find({references: "someref"}) doesn't work because references is not a valid array.
Document structure is not ideal for this kind of queries but you can use aggregation with $objectToArray operator:
db.collection.aggregate([
{$addFields: {refs: {$objectToArray: "$references"}}},
{$match: {"refs.v": "someref"}},
{$project:{refs: 0}}
])
If the number of subdocument fields you are looking into is small, then you can simply filter your collection using $or
db.collection.find(
{ $or: [
{"references.1": "someref"},
{"references.2": "someref"},
{"references.3": "someref"}
]} )

Sort mongodb query on multiple fields

I would like to sort a mongodb query that search for bloggers.
Here the document structure (simplified) of a Blogger :
{
posts : {
hashtags : [{
hashtag : String,
weight : Number
}]
},
globalMark : Number
}
People can search bloggers via an input text. Eg: They can write "fashion travel" and click on search button.
I would like as result to show up Bloggers who have posts that contain hashtags that match /fashion/i and /travel/i, sorted by relevancy. The relevancy depends on the globalMark and hashtag weight.
I know how to show up them skipping hashtag weight but don't know how to include this weight in my query....
Here my current query :
Blogger.find({
"$and" : [{
"posts.hashtags.hashtag" : {$regex: /fashion/i}
}, {
"posts.hashtags.hashtag" : {$regex: /travel/i}
}]
})
.sort("-globalMark")
How can I handle this weight ?
BIG THANKS !
First think: MongoDB is not a for search with like operator (if your data is big you will have some latency).
Second think: hashtags value need to be object or objects in array
Third: You can use
db.collectionName.find({
$and: [
{"posts.hashtags.hashtag" : {$regex: /fashion/i}},
{"posts.hashtags.hashtag" : {$regex: /travel/i}}
]
}).sort({
globalMark: 1, "posts.hashtags.weight": 1
})
I have made it using mongodb aggregation and $project pipeline stage. Basically $project let you modify result doc so I have used it to build a score regarding different fields then sort the aggregation on this built score.
Here the doc :
https://docs.mongodb.com/manual/reference/operator/aggregation/project/

How to update multiple documents with multiple condtions in MongoDB?

I have a MongoDB collections with various documents. Now I have the input document Ids in an array of cars which I want to update. Something like this.
req.body =
{ cars: [ '584cf6c126df866138a29408', '5852819e9693c27c136104bd' ],
name: 'Home' },
{ cars: [ '584d638242795854a091cbbf', '5842e09e372b786355ba50e7' ],
name: 'Office' } ]
Expected Operation
db.cars.update({_id : req.body[i].cars}, {name : req.body[i].name}, {new : true});
Expected Result
All four documents with ids are updated with their name field in the document.
Now one way to update cars is to have an async.each applied on the array and an aysnc.each on these two documents. That's the longer way of doing it. I was hoping if I have one async.each for these two arrays and somehow could cramp both the documents in a single query it would make the code look more elegant.
I have already gone through several pages and still haven't found anything wanted to know if this is possible in mongo or not?
At first you may need to convert your car ids String type to mongodb ObjectId that means like:
cars: [ ObjectId'584cf6c126df866138a29408'), ObjectId'5852819e9693c27c136104bd') ]
then use $in operator to match with documents.
can try this.
var ObjectId = require('mongodb').ObjectID;
var cars = req.body[i].cars.map(function (id) {
return new ObjectId(id);
})
db.cars.update({_id : {$in: cars}},
{$set : {name : req.body[i].name}},
{multi : true},
function(err, docs) {
console.log(docs);
});
Try using $in of mongodb in find query while doing update. See query below:
Model.update({_id : {$in: req.body[i].cars}},
{$set : {name : req.body[i].name}},
{multi : true});
So this way you have to run 2 queries to update the names.
See $in-doc to know more about the uses.
Hope this will help you.

How to check if multiple documents exist

Is there such a query that gets multiple fields, and returns which of these exists in the collection?
For example, if the collection has only:
{id : 1}
{id : 2}
And I want to know which of [{id : 1} , {id : 3}] exists in it, then the result will be something like [{id : 1}].
You are looking for the $in-operator.
db.collection.find({ id: { $in: [ 1, 3 ] } });
This will get you any documents where the id-field (different from the special _id field) is 1 or 3. When you only want the values of the id field and not the whole documents:
db.collection.find({ id: { $in: [ 1, 3 ] } }, { _id: false, id:true });
If you want to check provided key with value is present or not in collection, you can simply check by matching values and combining conditions using $or operator.
By considering id is different than _id in mongo.
You can use $or to get expected output and query will be as following.
db.collection.find({$or:[{"id":1},{"id":3}]},{"_id":0,"id":1})
If you want to match _id then use following query:
db.collection.find({$or:[{"_id":ObjectId("557fda78d077e6851e5bf0d3")},{"_id":ObjectId("557fda78d077e6851e5bf0d5")}]}

Mongodb : How to find documents in which fields match an ObjectId or a string?

I have some documents in a collection in Mongodb :
{_id : ObjectId('533af69b923967ac1801e113'), fKey : '533aeb09ebef89282c6cc478', ... }
{_id : ObjectId('5343bd1e2305566008434afc'), fKey : ObjectId('5343bd1e2305566008434afc'), ...} }
As you can see my field fkey can be set by a string or an ObjectId.
I would like to get all documents which match '533aeb09ebef89282c6cc478' or ObjectId('5343bd1e2305566008434afc').
But if i run :
db.mycollection.find({fkey : '533aeb09ebef89282c6cc478'})
I only get the first document of the collection.
Is there a way to configure Mongodb in order to get all documents which match the request without checking the type ?
Thanks for your help.
Pierre
There are two options for you here.
You could use mongo's $or operator:
db.mycollection.find({
$or: [
{ fKey: '533aeb09ebef89282c6cc478' },
{ fKey: ObjectId( '533aeb09ebef89282c6cc478' ) }
]
})
The $or operator performs a logical OR operation on an array of two or more <expressions> and selects the documents that satisfy at least one of the <expressions>.
You could also use the $in operator:
db.mycollection.find({
fKey: {
"$in": [ '533aeb09ebef89282c6cc478', ObjectId( '533aeb09ebef89282c6cc478' ) ]
}
})
The $in operator selects the documents where the value of a field equals any value in the specified array.
It sounds to me like these inconsistencies are not meant to be there. I recommend going through your code and data pipelines and figure out who/what is inserting the fKey value with an unknown datatype.