I have a mongodb (using mongoose) collection ("items") which includes an array ("images") among its properties. Some example documents:
[
{
"_id" : ObjectId("543fa67e9672ec37ebe3d026"),
"name" : "Alice",
"images" : [
{ url: "http://images.com/1.jpg" },
{ url: "http://images.com/2.jpg" },
{ url: "http://images.com/3.jpg" },
]
},
{
"_id" : ObjectId("543fa67e9672ec37ebe3d027"),
"name" : "Bob",
"images" : [
{ url: "http://images.com/4.jpg" },
{ url: "http://images.com/5.jpg" },
]
},
]
I want to implement a query which returns - along with other document properties - the array length (and not the array contents). I know I can get the array length with
db.items.aggregate([
{ "$project" : { "_id" : 0, "imagesLength" : { "$size" : "$images" } } }
])
But I need the imagesLength values along with the documents returned with a find:
db.items.findMany(
{ ...filter },
{ name: 1, imagesCount: 1 }
);
The question is: how can I get the array length along with the find results ?
You can do same as aggregation projection in find's second argument,
Starting in MongoDB 4.4, as part of making find projection consistent with aggregation’s $project stage,
db.items.find(
{ ...filter },
{
_id: 0,
name: 1,
images: { $size: "$images" }
})
Playground
You can add a match stage at first in your aggregation to filter the results. Then you can project all fields needed and generate the new ones.
db.items.aggregate([
{ "$match" : { ...filter },
{ "$project" : { "imagesLength" : { "$size" : "$images" }, "name": 1 } }
])
Related
I have an object inside of my pipeline that I want to set for a facet but am getting an empty object error.
{
_id: 123,
"NumLowerCodeRange" : "123",
"outputObject" : {
"1" : [
{
"$project" : {
"Indicator" : "1.0",
"_id" : 1
}
}
]
}
}
I want to be able to take this dataset and set the object to :
db.getCollection("test").aggregate([{
$facet: "$outputObject"}])
But I am getting an error of
'the $facet specification must be a non-empty object, but found: $facet: "$outputObject"' .
When I test the object out and hard code it, it works:
db.getCollection("test").aggregate([{
$set: {test: {$type: "$outputObject"}}},
{
$facet: {
"1" : [
{
"$project" : {
"Indicator" : "1.0",
"_id" : 1
}
}
]
}
}])
and I get the results I want:
{
"1" : [
{
"_id" : 123.0,
"Indicator" : "1.0"
}
]
}
I also try and create the object manually - and it works in mongosh as this
outputObject =
{
"1" : [
{
"$project" : {
"Indicator" : "1.0",
"_id" : 1
}
}
],
"2" : [
{
"$project" : {
"Indicator" : "2.0",
"_id" : 1
}
}
]
}
Enterprise rs0 [direct: primary] test> db.test.aggregate([{$facet:facetOutputs}])
[
{
'1': [ { _id: 123, Indicator: '1.0' } ],
'2': [ { _id: 123, Indicator: '2.0' } ]
}
]
Am I missing a comprehension of not being able to set an object in the aggregate pipeline?
I am struggling to create an aggregate query for my MongoDB database.
here is my input array
recipients = [1,2,7]
here is my database collection
{
"chapter": 1,
"targets": [
{
type: 'user',
recipient: 1
}
]
},
{
"chapter": 1,
"targets": [
{
type: 'user',
recipient: 2
}
]
},
{
"chapter": 2,
"targets": [
{
type: 'user',
recipient: 3
}
]
},
{
"chapter": 3,
"targets": [
{
type: 'user',
recipient: 4
}
]
},
the desired output
should be [] because 7 doesn't exist in targets.recipient in the collection
here is what I've tried so far
db.collection.aggregate([
{
$match: {
'targets.recipient': { $in: recipients },
},
}
])
Any suggestions, thank you.
The way $in works is that it returns the document if there's any match between it's value and the array you're passing as a parameter. It looks like in your case you can use $in for initial filtering but then you want to return the result only if the result set contains all the values from the input array. In order to achieve it you can use $group to get all matching results and then apply $all:
db.collection.aggregate([
{
$match: { "targets.recipient": { $in: [1,2,7] } }
},
{
$group: {
_id: null,
docs: { $push: "$$ROOT" }
}
},
{
$match: { "docs.targets.recipient": { $all: [1,2,7] } }
}
])
Mongo Playground
// only matched documents will be shown.
> db.targets.aggregate([ {$match:{"targets.recipient":{$in:[1,2,7]}}}, {$project:{chapter:1,targets:1}} ]).pretty();
{
"_id" : ObjectId("5f5de14c598d922a1e6eff4d"),
"chapter" : 1,
"targets" : [
{
"type" : "user",
"recipient" : 1
}
]
}
{
"_id" : ObjectId("5f5de14c598d922a1e6eff4e"),
"chapter" : 1,
"targets" : [
{
"type" : "user",
"recipient" : 2
}
]
}
>
I have pull friend request when it is accepted or canceled. So, when I try to pull it from array, it doesn't work.
It matches for 1 document but 0 document modified.
When I delete the requested_at field from user field, it works well.
Where do I make mistake at ?
MongoDB Document
{
"_id" : ObjectId("5cb18680aa024b2d441f93cc"),
"friends" : [],
"friend_requests" : [
{
"user" : {
"id" : ObjectId("5cb14fd7db537905c89e0a72"),
"requested_at" : ISODate("2019-04-14T17:51:00.588Z")
}
}
]
}
MongoDB Query
db.getCollection('users').updateOne(
{ _id: ObjectId("5cb18680aa024b2d441f93cc") },
{
$pull: {
friend_requests: {
user: {
id: ObjectId("5cb14fd7db537905c89e0a72")
}
}
}
});
Result
{
"acknowledged" : true,
"matchedCount" : 1.0,
"modifiedCount" : 0.0
}
Use dot notation to specify a condition:
db.users.updateOne(
{ _id: ObjectId("5cb18680aa024b2d441f93cc") },
{
$pull: {
"friend_requests": {
"user.id": ObjectId("5cb14fd7db537905c89e0a72")
}
}
});
I am trying to remove a comment object from an array in a mongodb using the $pull operator and it seems like I have the syntax correct but it is not modifying anything.
I have looked through all the examples given on Stack to make but it still keeps responding with
{ n: 0,
nModified: 0,
opTime:
{ ts:
Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1548664023 },
t: 1 },
electionId: 7fffffff0000000000000001,
ok: 1,
operationTime:
Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1548664023 },
'$clusterTime':
{ clusterTime:
Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1548664023 },
signature: { hash: [Binary], keyId: [Long] } } }
this is the field I currently have in the DB
{
"_id" : ObjectId("5be23d8aa365d853ddfd6f15"),
"__v" : 0,
"restaurant" : {
info about restaurant
},
"comments" : [
{
"id" : "61DSLu7fFcUZ2chA8-A6HQ",
"user" : "test",
"comment" : "test"
},
{
"comment" : "testing",
"user" : "testing",
"id" : ObjectId("5c3cd3a5647f180484a5ca18")
},
{
"restaurant_id" : "61DSLu7fFcUZ2chA8-A6HQ",
"comment" : "tacos",
"name" : "test",
"user_id" : ObjectId("5c48fdf47e9ed81b08536602")
},
{
"restaurant_id" : "61DSLu7fFcUZ2chA8-A6HQ",
"comment" : "tacos",
"name" : "test",
"comm_id" : ObjectId("5c49019f8528f31b2adfb914")
},
{
"restaurant_id" : "61DSLu7fFcUZ2chA8-A6HQ",
"comment" : "hello",
"name" : "test",
"comm_id" : ObjectId("5c490237fd6e781b52f801fe")
}
],
"likes" : {
"likes" : 6
}
Currently my model shows within my restaurants model
comments: [{
restaurant_id : String,
comment : String,
name : String,
comm_id : String,
}]
the update method I have currently
db.restaurants.updateOne({restaurant_id: rest_id},
{ $pull: { comments: { $in: [{comment: "hello"}] } }
}, { safe: true })
and also have tried
db.restaurants.updateOne({restaurant_id: rest_id},
{ $pull: { comments: { $in: {"comment": "hello"} } }
}, { safe: true })
as well as
db.restaurants.updateOne({restaurant_id: rest_id},
{ $pull: { comments: { comment: "hello"} } }
}, { safe: true })
and similar variation. I can't seem to pinpoint my mistake. the response seems like it is finding the correct restaurant field, but my $pull operator just isn't working properly. Is there something wrong with my syntax or does it not work in this scenario.
Ideally, I will use the comm_id field to remove the object from the array, but I am using comment: "hello" just to test.
Is it possibly because I have different fields in the first few comments?
do it simple it will works
db.restaurants.updateOne({restaurant_id: rest_id},
{ $pull: { comments.comment: "hello"} }
}, { safe: true })
[
{
_id: 555,
names:['John','Doe','David']
},
{
_id: 625,
names:['David','Mark','Carl']
},
{
_id: 299,
names:['Bill','Carlos','Ventus']
}
]
How can I return only the names(object) of all the object having _id in MongoDB ?
Please help me..
model.find({_id : { $exists : 1} }, "-_id names", { lean : true })
As each document in mongoDB has _id : model.find({}, "-_id names", { lean : true }) this would be fine.
You could also use mongo aggregate as follows :
model.aggregate({ $project : { _id : 0, names : 1 })