11

Basically with this I manage to return all my objects from a collection. How can I return a single element, for example    in the style of findOne({_ id:" 5e82d378527bb420a4001aaf ")?

I know how to use $match, but this returns various results.

let _id="5e82d378527bb420a4001aaf"

Noticia.aggregate([
    {
        $addFields: {
            like: {
                $cond: [{ $in: [_id, "$likes"] }, true, false]
            },
            dislike: {
                $cond: [{ $in: [_id, "$dislikes"] }, true, false]
            }

        }
    }

], (err, noticia) => {

    // console.log(trans);
    if (err) {
        return res.status(400).json({
            ok: false,
            err
        });
    }
    return res.status(200).json({
        ok: true,
        data: noticia
    });

})
2
  • .findOne returns null or object, while .aggregate returns list Commented Mar 31, 2020 at 22:58
  • @Valijon I just need to search for a record with a unique value. i don't know if i can use match in this case or if there is a better findOne () style path Commented Mar 31, 2020 at 23:02

3 Answers 3

12

Consider a sample names collection:

{ _id: 1, name: "Jack", favoriteColor: "blue" },
{ _id: 2, name: "James", favoriteColor: "red" },
{ _id: 3, name: "John", favoriteColor: "blue" }

and run the following three queries using findOne:

db.names.findOne( { _id: 1 } )
db.names.findOne()
db.names.findOne( { favoriteColor : "blue" } )

the result is same for the three queries:

{ "_id" : 1, "name" : "Jack", "favoriteColor" : "blue" }


The equivalent queries respectively using aggregation are the following, with the same result:

db.names.aggregate( [
  { $match: { _id: 1 } },
] )

db.names.aggregate( [
  { $limit: 1 }
] )


db.names.aggregate( [
  { $match: { "favoriteColor" : "blue" } },
  { $limit: 1 }
] )


db.collection.findOne definition says -

Returns one document that satisfies the specified query criteria on the collection or view. If multiple documents satisfy the query, this method returns the first document according to the natural order which reflects the order of documents on the disk.

With findOne if no document is found it returns a null. But an aggregation returns a cursor, and you can apply the cursor methods on the result.

Sign up to request clarification or add additional context in comments.

5 Comments

It returns array, how we can get only first document w/o in an array?
@ZeeshanAhmadKhalil If your code is returning an array, use the array element access code; e.g., myarray[0] gets the first element of the array. If your code is returning a cursor then use the cursor methods (there is a link in the above answer).
It returns the array but I want to get the first doc within the aggregate instead of returning the myarray and doing myarray[0]. Because I want to avoid using asyc await in my service function.
Aggregation query returns a cursor in case of native shell query. In case of some APIs the query can return an array. You can use $limit: 1 aggregation stage to return one document only - but it will be in a cursor or an array (as per the software you are using). You can create a single call, for example, db.names.aggregate( [ ... ] ).toArray()[0] in case of a cursor - note that if the aggregation query returns no data this will throw an error.
@ZeeshanAhmadKhalil (continued from previous comment) I suggest you create a new question explaining with code samples you are working on, software you are using, and other details for a proper answer you are looking for.
1

Just use $limit to limit no.of docs to be returned from aggregation pipeline :

Noticia.aggregate([
    {
        $addFields: {
            like: {
                $cond: [{ $in: [_id, "$likes"] }, true, false]
            },
            dislike: {
                $cond: [{ $in: [_id, "$dislikes"] }, true, false]
            }

        }
    } , {$limit :1} // will return first doc from aggregation result of '$addFields' stage

], (err, noticia) => {

    // console.log(trans);
    if (err) {
        return res.status(400).json({
            ok: false,
            err
        });
    }
    return res.status(200).json({
        ok: true,
        data: noticia
    });
 })

Or if you wanted to return random single doc try $sample.

5 Comments

Thank you, your responses are as good as ever. But I think I have not made myself understood. I just need to search for a record with a unique value. i don't know if i can use match in this case or if there is a better findOne () style way
@yavg : So you just wanted to return one doc from aggregation or multiple docs ? If you wanted to return multiple docs then what do you wanted to do with matched doc from $match?
@yavg : Then all you can do is $match
can you help me please with this hard question for me? stackoverflow.com/questions/61000005/…
You always shake my hand when I need you the most. Can you help me please? stackoverflow.com/questions/61004259/…
1
//Express and mongoose
exports.getData = (req, res) => {

    Noticia.aggregate([
        {
            $addFields: {
                like: {
                    $cond: [{ $in: [_id, "$likes"] }, true, false]
                },
                dislike: {
                    $cond: [{ $in: [_id, "$dislikes"] }, true, false]
                }
    
            }
        }  
    ]
    ).then( data=>{
        res.send(data[0]); //return one document in format { ..... }
    }).catch(err => {
        res.status(500).send({ 
          message: err.message 
        });
    });
}

1 Comment

This code uses the express and mongoose framework and returns a single document, without using brackets. Show the document in braces

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.