Filter array and document in MongoDB - javascript

Schema
[
{
_id:"doc1",
type:"SR",
title:"...",
description:"...",
author:"5",
posts:[
{
author:"1",
title:"..."
},
{
author:"2",
title:"..."
},
{
author:"1",
title:"..."
}
]
},
{
_id:"doc2",
type:"SA",
title:"...",
description:"...",
posts:[],
author:"5"
}
]
Every Document will have type either SA or SR. If type is SA then posts will be an empty array, otherwise it'll non empty.
Now, i want to get document and array elements based on certain conditions.
if type is SA and authorId=5 then return the entire document.
if type is SR then return the elements of posts where authorId=1
When type is SA then i would like to get title,description,.. of the document otherwise get the posts by filter.
My Query
Using mongoose
Blog.find({
$or: [
{
$and: [
{ type: "SA" },
{ authorId:"5" }
]
},
{
"posts.authorId": "1"
}
]
}, {
posts: {
$filter: {
input: "$posts",
as: "post",
cond: {
$eq: ["$$post.authorId", "1"]
}
}
}
})
.then(posts => {
console.log(posts)
})
.catch(err => {
console.log(err);
})
Returned document
[
{
_id:"doc1",
posts:[
{
author:"1",
title:"..."
},
{
author:"1",
title:"..."
}
]
},
{
_id:"doc2",
posts:[]
}
]
How can i include other attribute of doc2?

Related

how to catch mongo change streams when one key in object gets updated

I am using the mongo change stream to update some of my data in the cache. This is the Documentation i am following.
I want to know when one of the keys in my object gets updated.
Schema :- attributes: { position: { type: Number } },
How will I come to know when the position will get updated?
This is how my updateDescription object looks like after updation
updateDescription = {
updatedFields: { 'attributes.position': 1, randomKey: '1234'},
removedFields: []
}
Tried this and its not working
Collection.watch(
[
{
$match: {
$and: [
{ operationType: { $in: ['update'] } },
{
$or: [
{ 'updateDescription.updatedFields[attributes.position]': { $exists: true } },
],
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
I was able to fix it like this,
const streamUpdates = <CollectionName>.watch(
[
{
$project:
{
'updateDescription.updatedFields': { $objectToArray: '$updateDescription.updatedFields' },
fullDocument: 1,
operationType: 1,
},
},
{
$match: {
$and: [
{ operationType: 'update' },
{
'updateDescription.updatedFields.k': {
$in: [
'attributes.position',
],
},
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
and then do something with the stream
streamUpdates.on('change', async (next) => {
//your logic
});
Read more here MongoDB

Use mongoDB $lookup to find documents in another collection not present inside an array

I'm using the aggregate framework to query a collection and create an array of active players (up until the last $lookup) after which I'm trying to use $lookup and $pipeline to select all the players from another collection (users) that are not present inside the activeUsers array.
Is there any way of doing this with my current setup?
Game.aggregate[{
$match: {
date: {
$gte: ISODate('2021-04-10T00:00:00.355Z')
},
gameStatus: 'played'
}
}, {
$unwind: {
path: '$players',
preserveNullAndEmptyArrays: false
}
}, {
$group: {
_id: '$players'
}
}, {
$group: {
_id: null,
activeUsers: {
$push: '$_id'
}
}
}, {
$project: {
activeUsers: true,
_id: false
}
}, {
$lookup: {
from: 'users',
'let': {
active: '$activeUsers'
},
pipeline: [{
$match: {
deactivated: false,
// The rest of the query works fine but here I would like to
// select only the elements that *aren't* inside
// the array (instead of the ones that *are* inside)
// but if I use '$nin' here mongoDB throws
// an 'unrecognized' error
$expr: {
$in: [
'$_id',
'$$active'
]
}
}
},
{
$project: {
_id: 1
}
}
],
as: 'users'
}
}]
Thanks
For negative condition use $not before $in operator,
{ $expr: { $not: { $in: ['$_id', '$$active'] } } }

How to delete an element in a sub sub document mongoosejs

how to delete the "extras" with "id_extra = 8523" of the "book" "id_book = 8522" of that particular user?, I currently use mongoosejs but I didn't succeed, I tried many stuffs, but whatever I tried was working just till the first level of nested doc.
{
"_id":{
"$oid":"5e32fce08919b53ad66cf694"
},
"user_id":{
"$numberInt":"258787"
},
"username":"daaaa",
"firstname":"davide",
"api_key":"7b031c21edf1237c554867622ad1154f",
"books":[
{
"_id":{
"$oid":"5e356323a0ef6319ebb60162"
},
"id_book":{
"$numberInt":"8522"
},
"blob_annotation":null,
"extra_id":{
"$numberInt":"995176"
},
"extras":[
{
"_id":{
"$oid":"5e356324a0ef6319ebb60163"
},
"id_extra":{
"$numberInt":"8523"
},
"type":"gallery_audio",
"label":"Inverno a Boscodirovo"
},
{
"_id":{
"$oid":"5e356324a0ef6319ebb60164"
},
"id_extra":{
"$numberInt":"8524"
},
"type":"gallery_audio",
"label":"Storia di Primavera"
}
],
"raccolte":[
]
}
],
}
Try using elemMatch in conjunction with $:
db.books.update(
{
books: {
$elemMatch: {
"id_book": 8522,
"extras.id_extra": 8523
}
},
user_id: 258787
},
{
$pull: {
"books.$.extras": {
"id_extra": 8523
}
}
}
)
You may do this trick: Filter "extras" with "id_extra = 8523" of the "book" "id_book = 8522" and save documents again in MongoDB
db.collection.aggregate([
{
$match: {
"books.id_book": 8522
}
},
{
$addFields: {
"books": {
$reduce: {
input: "$books",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
_id: "$$this._id",
id_book: "$$this.id_book",
blob_annotation: "$$this.blob_annotation",
extra_id: "$$this.extra_id",
raccolte: "$$this.raccolte",
extras: {
$filter: {
input: "$$this.extras",
cond: {
$ne: [
"$$this.id_extra",
8523
]
}
}
}
}
]
]
}
}
}
}
}
])
MongoPlayground

mongodb find documents using condition and update another field in the respective document

I want to find any document in my collection that:
its hobby field is empty
or its hobby field doesn't exist
and then set the value of its hobby field to be equivalent of its sports field.
db.myCollection.update(
{ $or: [{"hobby": {$exists: false} },{"hobby": ""}]}
, {
$set: {
hobby: ????sports
}
}, {
multi: true
},
function(err, result) {
console.log(result);
console.log(err);
})
With this command above, I suppose I will be passing the value of sports as fixed value to all matching documents. is there any way to pick up its corresponding sports value and set it to hobby?
here is the modified version that updates correctly the values:
db.myCollection.find({
$or: [{ "hobby": { $exists: false } }, { "hobby": "" }]
}).toArray().forEach(function (item) {
db.myCollection.update(
{ _id: item._id },
{ $set: { hobby: item.sports } },
{ multi: true }
)
})
})
You have to do this in 2 queries:
db.myCollection.find({
$or: [{ "hobby": { $exists: false } }, { "hobby": "" }]
}).toArray().forEach(function (item) {
db.myCollection.update(
{ _id: item._id },
{ $set: { hobby: item.sports } },
{ multi: true }
)
})
})

(mongoDB) find with empty or null values

how to make a mongodb collection find (db.collection.find) with empty values?
currently i have:
function test(s) {
if (!s) {
return null;
} else {
return s;
}
}
var content = {
date: {
from: '2017-10-15',
to: '2017-11-15'
},
'name': 'some text', //this can be null or empty
'text': 'some other text' //this can be null or empty
}
col.find({
"date": {
$gte: new Date(content.date.from),
$lte: new Date(content.date.to)
},
"name": {
$ne: {
$type: null
},
$eq: test(content.name)
},
"text": {
$ne: {
$type: null
},
$eq: test(content.text)
},
}).toArray((err, items) => {
console.log(items)
});
but it returns an empty array, because "name" or "text" is null / an empty string,
i want that it query only the values that have something specified or ignore it (like content.name is something in it or its empty)
how do i get it? i already searched ... but didnt found something
thanks!
( already testet mongoDB : multi value field search ignoring null fields)
Versions:
Node: 8.9.0
(npm) mongodb: 2.2.33
mongodb: 3.4
Try using $and, $or operators. Something like.
col.find({
$and:[
{"date": {$gte: new Date(content.date.from),$lte: new Date(content.date.to)}},
{"$or":[{"name": {$ne: {$type: null}}},{"name":test(content.name)}]},
{"$or":[{"text": {$ne: {$type: null}}},{"text":test(content.text)}]}
]
}).toArray((err, items) => {
console.log(items)
});
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': content.text }
]
}
]
})
Edited:
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name':'' }
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': '' },
{ 'text': content.text }
]
}
]
})
null and empty is different, you need to add one more condition for empty string in query.
Logical Query Operators

Categories

Resources