How do I return all results that don't contain a certain value in mongodb - mongodb

I have some data in my mongodb database that looks similar to this:
[
{
username: 'will',
post: 'some random post',
user_id: '12345',
_id: 0
},
{
username: 'jogno',
post: 'some random post',
user_id: '23412',
_id: 1
},
{
username: 'aflack',
post: 'some random post',
user_id: '24332',
_id: 2
}
]
If my user_id is 12345, I want my query to return the other 2 posts where the user_id does NOT equal 12345. However when I use the query below it just returns all 3 posts, am I missing something or is there a different and better way to do this? Thanks
Post.find(
{ user_id: { $not: 12345 } }
)
SOLUTION:
I had to use $ne instead of $not

In your database, the user_id is a string, but in your query you are selecting a number.
Also, you should be using $ne for this.
Try $ne: "12345"

Related

MongoDB - how I add a UUID column to existing collection based on values from current entries?

I have 'Users' collection which has two columns, '_id' and 'userName', both of type string.
I want to add third column 'UserId' which will be UUID wrapping the id from _id column.
Tried few ways but without any success.
For example:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex"
}
I want it to be:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex",
UserId: UUID("fe83f869-154e-4c26-a5db-fb147728820f")
}
I tried something like:
db.Users_temp.update(
{},
{ $set: {"UserId": UUID("$_id") } },
false,
true
)
But it results in columns with value UUID("----")
Will appreciate any help.
Ok,
Found a solution to my problem.
db.Users_temp.find().forEach(function(user) {
db.Users_temp.update(
{"_id" : user._id},
{ "$set": {"UserId": UUID(user._id)} }
)
})
this will work
i am not sure why but this works only with set operation as an array rather than as a object
db.Users_temp.update({},[{$set: {'UserId': '$_id'}}])

Building mongo query

I have a model like this:
[{item: {
_id: 123,
field1: someValue,
price: {
[_id: 456,
field1: anotherValue,
type: []],
[_id: 789,
field1: anotherValue,
type: ['super']]
}
}]
I need to find an item by 3 parameters: item _id, price _id, and check if price type array is empty. And check it in one price field.
Model.findOneAndUpdate({_id: 123, "price._id": 456, "price.type": {size:0})
This query always returns item, cause search in different prices.
Model.findOneAndUpdate({_id: 123, price: {id: 456, type: {size:0})
This query returns error (cast array value or something like this).
tried to build query with $in, $and, but still getting an error
Use $elemMatch:
The $elemMatch operator matches documents that contain an array field
with at least one element that matches all the specified query
criteria.
db.inventory.find({
price: {
"$elemMatch": {
_id: 456,
type: {
$size: 0
}
}
}
})

Checking for similar records in mongodb across multiple fields.

In mongodb, I have a collection of people with the schema below. I need to write an aggregation to find possible duplicates in the database by checking:
If another person with same firstName, lastName & currentCompany exists.
Or, if another person with the same currentCompany & currentTitle exists.
Or, if another person has the same email (which is stored as an object in an array)
Or, if someone else has the same linkedIn/twitter url.
Is there a straightforward way of checking for duplicates based on the above cases w/ a mongodb aggregation? This question is close to what I'm looking for, but I need to check more than just one key/value.
{ _id: 'wHwNNKMSL9v3gKEuz',
firstName: 'John',
lastName: 'Doe',
currentCompany: 'John Co',
currentTitle: 'VP Sanitation',
emails:
[ { address: 'Anais.Grant#hotmail.com',
valid: true } ],
urls:
{ linkedIn: 'http://linkedin.com/johnDoe',
twitter: 'http://twitter.com/#john',
}
}
Thanks!
We can achieve it is using the following
$and, $or, $ne.
Note:- You need to feed one record as input for the conditions to match it with other records for eliminating the duplicates
I have given a sample query which will be filtering your collection for these two criterias, you can add the rest of your conditions to get the final result
If another person with same firstName, lastName & currentCompany exists.
Or, if someone else has the same linkedIn/twitter url.
db.yourcollection.find({
$and: [{
$or: [{
firstName: {
$ne: 'John'
}
}, {
lastName: {
$ne: 'Doe'
}
}, {
currentCompany: {
$ne: 'John Co'
}
}]
}, {
$or: [{
"urls.linkedIn": {
$ne: 'http://linkedin.com/Doe'
}
}]
}]
})

How can I retrieve all the fields when using $elemMatch?

Consider the following posts collection:
{
_id: 1,
title: "Title1",
category: "Category1",
comments: [
{
title: "CommentTitle1",
likes: 3
},
{
title: "CommentTitle2",
likes: 4
}
]
}
{
_id: 2,
title: "Title2",
category: "Category2",
comments: [
{
title: "CommentTitle3",
likes: 1
},
{
title: "CommentTitle4",
likes: 4
}
]
}
{
_id: 3,
title: "Title3",
category: "Category2",
comments: [
{
title: "CommentTitle5",
likes: 1
},
{
title: "CommentTitle6",
likes: 3
}
]
}
I want to retrieve all the posts, and if one post has a comment with 4 likes I want to retrieve this comment only under the "comments" array. If I do this:
db.posts.find({}, {comments: { $elemMatch: {likes: 4}}})
...I get this (which is exactly what I want):
{
_id: 1,
comments: [
{
title: "CommentTitle2",
likes: 4
}
]
}
{
_id: 2,
comments: [
{
title: "CommentTitle4",
likes: 4
}
]
}
{
_id: 3
}
But how can I retrieve the remaining fields of the documents without having to declare each of them like below? This way if added more fields to the post document, I wouldn't have to change the find query
db.posts.find({}, {title: 1, category: 1, comments: { $elemMatch: {likes: 4}}})
Thanks
--EDIT--
Sorry for the misread of your question. I think you'll find my response to this question here to be what you are looking for. As people have commented, you cannot project this way in a find, but you can use aggregation to do so:
https://stackoverflow.com/a/21687032/2313887
The rest of the answer stands as useful. So I think I'll leave it here
You must specify all of the fields you want or nothing at all when using projection.
You are asking here essentially that once you choose to alter the output of the document and limit how one field is displayed then can I avoid specifying the behavior. The bottom line is thinking of the projection part of a query argument to find just like SQL SELECT.It behaves in that * or all is the default and after that is a list of fields and maybe some manipulation of the fields format. The only difference is for _id which is always there by default unless specified otherwise by excluding it, i.e { _id: 0 }
Alternately if you want to filter the collection you nee to place your $elemMatch in thequery itself. The usage here in projection is to explicitly limit the returned document to only contain the matching elements in the array.
Alter your query:
db.posts.find(
{ comments: { $elemMatch: {likes: 4}}},
{ title: 1, category: 1, "comments.likes.$": 1 }
)
And to get what you want we use the positional $ operator in the projection portion of the find.
See the documentation for the difference between the two usages:
http://docs.mongodb.org/manual/reference/operator/query/elemMatch/
http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/
This question is pretty old, but I just faced the same issue and I didn't want to use the aggregation pipeline as it was simple query and I only needed to get all fields applying an $elemMatch to one field.
I'm using Mongoose (which was not the original question but it's very frequent these days), and to get exactly what the question said (How can I retrieve all the fields when using $elemMatch?) I made this:
const projection = {};
Object.keys(Model.schema.paths).forEach(key => {
projection[key] = 1;
});
projection.subfield = { $elemMatch: { _id: subfieldId } };
Model.find({}, projection).then((result) => console.log({ result });

JugglingDB MongoDB Array of IDs

I'm using MongoDB adapter of Juggling-DB.
How can I run the equivalent of the following SQL query (IDs are fake)
SELECT * FROM APPS
WHERE
active = 1
AND (
user_id = '12345'
OR
id IN ('456', '789', '012')
)
that is "active apps that either belong to the given user or are available to all".
I tried the following:
{
where: {
active: true,
or: [
{
user_id: '12345'
},
{
_id: {
in: ['456', '789', '012']
}
}
]
}
}
But it returns nothing. Looking at the source code my wild guess is that it only converts strings to MongoDB.ObjectID when _id is a single string, not an array.
The mongodb query should be like:
db.apps.find({active: true, "$or": [{"user_id": "12345"}, {"_id": { $in: ['1', '2', '3']}}]})