Content Developer II at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
132579 stories
·
29 followers

Windows 10 end of support for Teams Rooms on Windows

1 Share

Effective October 14, 2025, Teams Rooms on Windows 10 devices will no longer receive security and feature updates, making it essential to upgrade to Windows 11 to continue enjoying the latest productivity, security, and management features. As we approach the end of support for Windows 10 on Teams Rooms, we want to offer a clear path forward for this critical infrastructure in your organization.

During this transitional period, Teams Rooms and Teams Rooms Pro Management software will continue to support and test the latest Teams Rooms app on Windows 10 22H2 (version 10.0.19045) until October 14, 2025. After this date, support and updates for the Teams Rooms apps on Windows 10 will end. We encourage you to utilize the Teams Rooms Pro Management Room Inventory export or the Windows 11 readiness checker to identify which devices will need an upgrade or replacement.

Most Teams Rooms devices running Windows 10 have been automatically upgraded to Windows 11. However, certain certified devices, such as Lenovo Hub 500 (i5-7500T), HP Slice G2 (i5-7500T), HP Elite Slice (i5-7500T), Yealink NUC – NUC7i5DNKE (i5-7300U), and Crestron Skull Canyon (i7-6770HQ), cannot be upgraded to Windows 11 and will need to be replaced. This list is not exhaustive, so we recommend contacting your device manufacturer for questions on specific models affected.

For more detailed information on Operating System support for the Teams Rooms application, please visit Teams Rooms app and Windows versioning support - Microsoft Teams | Microsoft Learn. Additionally, refer to the Microsoft product lifecycle notices for Windows 10 Enterprise and Windows 10 IoT Enterprise, and plan for Windows 11 with the resources available on Microsoft Learn.

We are excited to continue our focus on the future of Teams Rooms on Windows so that we can bring you more of the best possible meeting experiences.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Google AI Developers Community Spotlight Contest

1 Share
The Google AI Developers Community Spotlight Contest is seeking innovative, diverse projects using Google's AI tools like Gemini and Gemma to create code repositories, videos, documentation, and more.
Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Auth0 Announces Auth for GenAI

1 Share
Learn how Auth for GenAI helps secure your GenAI apps. Join the waitlist to be the first to know when Auth for GenAI is available in early access

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Enhancing the security of Microsoft Edge Extensions with the new Publish API – What’s next?

1 Share
In our previous blog post, Enhancing the security of Microsoft Edge extensions with the new Publish API, we introduced the new Publish API, which brings key security enhancements to Microsoft Edge extension developers. As mentioned in the Publish API documentation, support for the previous version of the API was planned to end on December 31, 2024. In this blog post, we’ll discuss the next steps and what extension developers need to do to ensure your extensions continue to function smoothly.

Extended deprecation period

Based on your feedback, we have extended the deprecation period. Support for the previous version of the Publish API will now end on January 10, 2025. Starting on January 10, version 1 of the Publish API will be deprecated. Developers who have not yet transitioned to the new Publish API may experience disruptions in their continuous integration or delivery (CI/CD) pipelines, leading to updates not being published. This change is part of our ongoing commitment to enhancing the security of the publishing process and protecting your extensions.

What to do if you haven't migrated to the new API yet

If you have not migrated your CI/CD code to use the new Publish API yet, your already published extensions will still function, but you won't be able to publish new versions. Start using the new Publish API as soon as possible as it is a significant step towards enhancing the security of your Microsoft Edge extensions. To learn how to start using the new Publish API, please check out the updated documentation. In summary:
  • Opt-in to the new API key management experience in Partner Center.
  • Generate your Client ID and API key in Partner Center. The API key is valid for 72 days, compared to the previous 2-year expiration period. You will receive email notifications before your API key expires.
  • In your CI/CD publishing code, instead of using the token that version 1 of the Publish API generated from credentials, use the Client ID and API key.
  • Deprecate any old CI/CD pipelines that may be using the previous version of the API.

Share your feedback

We encourage you to share your feedback and questions on our GitHub developer community. Your input is invaluable in helping us improve the security and functionality of Microsoft Edge extensions.
Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Firestore Queries for SQL Minds

1 Share

Create an app fast with Firebase, even if you’re intimidated by NoSQL databases—the translation of queries to SQL is easier than you think.

SQL databases are quite different than NoSQL databases, so you must think a little differently when modeling your data. However, most translations from SQL code to NoSQL are identical or easier. Here, we use the Firebase Modular API, but the firebase-admin API will be the same.

TL;DR

Firestore is a document database that doesn’t allow joins. You can simulate them by duplicating your data. Most regular queries, however, work as expected. The lack of a schema allows you to get up and going extremely quickly. You need to learn the data modeling patterns.

Introduction

Firestore is a NoSQL document database.

Tables

  • A table is a collection or subcollection. A row is a document.

Schema

  • You must declare a schema in SQL; you don’t need one in NoSQL.
  • Each document can have different kinds of data, although this would not be useful.

Create

You create a table when you create a document. A table does not exist without a document.

Alter

There is nothing to alter.

Drop

To drop a table, you must delete all documents in a collection. This can also be done in the Firebase Console.

Constraints

There is no schema, but you can declare constraints using Firebase Rules.

Naming Conventions

You will usually see camel case field names instead of snake case.

Primary Key

Each document has a unique path. The documentId() of the document is the primary key. In the collection posts/2xelskel, the 2xelskel is the document ID. You can use any alphanumeric string, as well as _ characters. Otherwise, it will be automatically generated.

Insert

You can insert data in SQL by declaring each field and value.

SQL

INSERT INTO posts (title, content, created_by, created_at)
VALUES (
    'My First Post', 
    'This is the content of my first post.', 
    1, 
    NOW()
);

Firestore

addDoc(
collection(db, 'posts'),
{
title: 'My First Post',
    content: 'This is the content of my first post.',
    createdBy: 1,
    createdAt: serverTimestamp()
  }
});

Notice the serverTimestamp() function, which will use the date on the server. Since Firestore can be safely run on the client, this would be secured in Firestore Rules.

Update

Updating is basically the same.

SQL

UPDATE posts
SET title = 'Updated Post Title',
    content = 'This is the updated content of the post.',
    updated_at = NOW()
WHERE post_id = 1;

Firestore

updateDoc(
collection(db, 'posts', '1'),
{
title = 'Updated Post Title',
    content = 'This is the updated content of the post.',
    updatedAt: serverTimestamp()
  }
});

Notice the document ID is 1 in this case. The ID will probably be a uniquely generated string in a real application.

Upsert

You can upsert a document with setDoc.

SQL

INSERT INTO posts (id, title, content, created_by, created_at, updated_at)
VALUES (1, 'Upserted Post', 'This is the upserted content.', 1, NOW(), NOW())
ON CONFLICT (id)
DO UPDATE SET 
    title = EXCLUDED.title,
    content = EXCLUDED.content,
    author_id = EXCLUDED.created_by,
    updated_at = NOW();

This will vary between SQL languages.

setDoc(
doc(db, 'posts', '1'),
{
title: 'Upserted Post',
content: 'This is the upserted content.',
createdBy: 1,
createdAt: serverTimestamp(),
updatedAt: serverTimestamp()
}, { merge: true }
});

setDoc behaves like addDoc without the { merge: true } parameter.

Select

In Firestore, you can only select all fields from a document unless you use the REST API with your own code.

SQL

SELECT * FROM posts;

Select all posts.

Firestore

query(
collection(db, 'posts')
);

Exists

In SQL, you SELECT first.

SQL

SELECT EXISTS (
    SELECT 1
    FROM posts
    WHERE id = 1
);

Firestore

const postSnap = await getDoc(doc(db, 'posts', '1'));
const exists = postSnap.exists();  

In Firestore, you must read the document to check its existence.

Limit

Of course, we limit our selection to one or more in actual use cases. We don’t want all documents in a collection or all rows in a table.

SQL

SELECT * FROM posts LIMIT 1;

Firestore

query(
collection(db, 'posts'),
limit(1)
);

There is nothing surprising here.

Where

Firestore queries use AND by default, but you can also add OR queries.

SQL

SELECT * FROM posts
WHERE
    (a = 1 AND c = 3) OR
    (a = 1 AND d = 4) OR
    (b = 2 AND c = 3) OR
    (b = 2 AND d = 4);

Firestore

query(
  collection(db, 'posts'),
  or(
    and(where('a', '==', 1), where('c', '==', 3)),
    and(where('a', '==', 1), where('d', '==', 4)),
    and(where('b', '==', 2), where('c', '==', 3)),
    and(where('b', '==', 2), where('d', '==', 4))
  )
);

⚠️ Unlike in SQL, each query has a strict limit of 30 disjunctions.

In

You can search for IN as well in Firestore.

SQL

SELECT *
FROM posts
WHERE created_by IN (1, 2, 3);

Firestore

query(
collection(db, 'posts'),
where('created_by', 'in', [1, 2, 3])
)

Keep in mind this is a simplification of:

query(
collection(db, 'posts'),
or(
where('created_by', '==', 1),
where('created_by', '==', 2),
where('created_by', '==', 3)
)
);

The same goes for SQL. IN is just several OR clauses on the same field, condensed.

Order By

You can order your data similar to SQL.

SQL

SELECT * FROM posts
ORDER BY created_by ASC, created_at DESC;

Firestore

query(
collection(db, 'posts'),
orderBy('createdBy'),
orderBy('createdAt', 'desc')
);

The default sort order is asc.

An orderBy also sorts data, so the field must exist. Otherwise, it is filtered out.

⚠️ Changing orderBy fields requires a composite index for each query. If you change the field, you need another index.

Inequalities

You can have inequalities on multiple fields.

SQL

SELECT * FROM cities
WHERE population > 1000000
  AND density < 10000;

Firestore

query(
  collection(db, 'cities'),
  where('population', '>', 1000000),
  where('density', '<', 10000),
);

Order index fields by equalities followed by most selective range or inequality field.

⚠️ Order fields in decreasing order of query constraint selectivity.

⚠️ Queries with range or inequality filters on document fields and only equality constraints on the document key (__name__) aren’t supported.

⚠️ Cloud Firestore limits the number of range or inequality fields to 10. This prevents queries from becoming too expensive to run.

NOT Equal

You can only have a != on one field in Firestore per query.

SQL

SELECT * FROM cities
WHERE capital != false;

Firestore

query(
collection(db, 'cities'),
where("capital", "!=", false)
);

⚠️ A != query clause might match many documents in a collection. To control the number of results returned, use a limit clause.

Not-equal queries exclude documents where the given field does not exist.

For multiple not equals on the same field, use not-in.

Incrementing

You don’t need to increment columns in SQL until your database gets big. Either way, the code is simple.

SQL

UPDATE posts
SET views = views + 1
WHERE id = 1;

Firestore

updateDoc(
doc(db, 'posts', '1'),
{
views: increment(1)
}
});

This is more useful in NoSQL databases. You can also use increment(-1) for decrementing.

Count

Counting can get complex in Firestore, but generally, you want to count on the server.

SQL

SELECT COUNT(*) AS post_count
FROM posts
WHERE created_by = 1;

Firestore

const countSnap = await getCountFromServer(
  query(
    collection(db, 'posts')
  )
);
const postCount = countSnap.data().count;

You need two separate calls to count a query and return the query results.

Other Count Aggregations

You can also do sum and average aggregations.

min and max are not supported.

See Aggregation Queries.

Sorting by Count

You can’t sort by a count directly, so you must first count in Firestore.

SQL

Let’s say we want to get all users and them by post_count, or the number of posts they have.

SELECT users.*, COUNT(posts.id) AS post_count
FROM users
JOIN posts ON users.id = posts.author_id
GROUP BY users.id
ORDER BY post_count DESC;

Firestore

In Firestore, we must create the post_count with each post created in the user’s document. We can do this in a batch transaction.

  const userRef = doc(db, 'users/1');
  const postRef = doc(collection(db, 'posts'));

  const batch = writeBatch(db);

  batch.set(userRef, {
      postCount: increment(1)
  }, { merge: true });

  batch.set(postRef, {
      createdBy: auth.currentUser,
      createdAt: serverTimestamp(),
      title: 'Some post',
      content: 'post content here'
  });

  batch.commit();
}

And finally, we can sort the documents later.

query(
collection(db, 'users'),
orderBy('postCount', 'desc')
);

You can secure this in Firestore Rules or create a Firebase Trigger Function on onCreate that automatically increments and decrements the user document.

Counters get extremely complicated in Firestore. See Four Ways to Count in Firestore for niche cases.

Unique and Distinct

The only way to keep something unique is to set it as the document ID in Firestore. If you want a unique field, you must put it in two places in a transaction.

Unique Usernames

For uniqueness, we can save a username in the users collection on the user document and in a usernames collection in a single transaction. We can use Firestore Rules to secure this.

SQL

SELECT DISTINCT username
FROM users
ORDER BY username ASC;

Firestore

const batch = writeBatch();

batch.set(
    doc(`usernames/${username}`),
    {
        uid,
        username
    }
);

batch.set(
    doc(`users/${uid}`),
    {
        username
    },
    { merge: true }
);

await batch.commit();

If you update the username, also consider removing the old username in the usernames collection first.

query(
collection(db, 'usernames'),
orderBy('usernames')
);

Distinct Countries

If you want to search for all countries users belong to, you must also store a unique countries collection.

SQL

SELECT country, COUNT(*) as user_count
FROM users
GROUP BY country
ORDER BY user_count DESC;

Firestore

const batch = writeBatch();

batch.set(
    doc(`countries/${country}`),
    {
        uid,
        country
        userCount: increment(1)
    }
);

batch.set(
    doc(`users/${uid}`),
    {
        country
    },
    { merge: true }
);

await batch.commit();

You could also create the countries using a Firebase Trigger Function. You should also consider keeping a count of the number of users in each country. This could come in handy if you want to search for the most popular country your users belong to.

query(
collection(db, 'countries'),
orderBy('userCount', 'desc')
);

️ The common theme you start to see is that Firestore requires you to create your database for the queries instead of vice versa.

Like

There is no LIKE equivalent in Firestore.

SQL

SELECT country
FROM users
WHERE country LIKE 'Uni%';

However, there is a startsWith hack you can use.

Firestore

export const startsWith = (
    fieldName: string,
    term: string
) => {
    return [
        orderBy(fieldName),
        startAt(term),
        endAt(term + '~')
    ];
};

This function can be used to find a string that starts with a term. It only works in parent objects and does not work with arrays or objects.

query(
collection(db, 'users'),
...startsWith('country', 'Uni')
);

Use an external database or store your search index inside Firestore if you want Fuzzy Searching capabilities. You can do this with Vectors or a custom function like Soundex.

Inner Joins

You can easily do an inner join in Firestore by querying two different collections, but this will cost you an extra document read and could potentially slow down your app.

Many-to-One

The class example is adding user information to a post.

SQL

SELECT 
  p.id AS post_id,
  p.title AS post_title,
  p.content AS post_content,
  jsonb_build_object(
    'id', u.id,
    'name', u.name,
    'email', u.email
  ) AS created_by
FROM posts p
JOIN users u ON p.created_by = u.id;

You could easily do this without JSON, but I wanted an equivalent object.

Firestore

addDoc(
doc(db, 'posts', 'post-id'),
{
title: 'some title',
content: 'some content',
createdBy: {
uid: auth.currentUser.uid,
displayName: 'auth.currentUser.displayName,
username: 'get username from user document or custom claim'
}
}
});

This could be done in many ways, but the query is easy.

getDoc(
doc(db, 'posts', 'post-id-here')
);

Again, you need to consider when a user updates their username, displayName or other profile information. You should create a Firebase Trigger Function to handle it.

Many-to-Many Tags

Here, we have posts and tags. Each post can have many tags, but you won’t have an infinite number of tags on a post. Firestore allows you to store data as arrays and search based on the array. An array works perfectly in this case.

SQL

In SQL, we may have a tags table with the user_id.

SELECT p.id AS post_id, p.title, p.content, t.tag
FROM posts p
LEFT JOIN tags t ON p.id = t.post_id
ORDER BY p.id;

Or, we may have a junction table post_tag.

SELECT p.id AS post_id, p.title, p.content, t.name AS tag_name
FROM posts p
JOIN post_tag pt ON p.id = pt.post_id
JOIN tags t ON pt.tag_id = t.id
ORDER BY p.id;

Firestore

In Firestore, we must create the tags in two different places, similar to the unique index.

const batch = writeBatch(db);

const tags = ['tag1', 'tag2'];

// add tags array when adding post
batch.set(
doc(db, 'posts', 'some-post-id'), {
  tags,
  title: 'some title',
  content: 'some content',
  createdBy: auth.currentUser.uid,
  createdAt: serverTimestamp()
});

// create a tag document
tags.forEach(tag => {
batch.set(doc(db, 'tags', tag), {
  postCount: increment(1)
}, { merge: true });
});

await batch.commit();

️ We must also remember to decrement the postCount on tags when a post is modified or deleted. This should be done with Firebase Functions, as Firestore Rules would get too complex for multiple tags. Firestore Rules also do not have loops.

query(
collection(db, 'posts')
);

The tags will already be attached to the post document.

Complex Queries

Firestore does not handle complex queries, but there are workarounds for most use cases. This post only scratches the surface.

Documents vs. Tables

A NoSQL database is quite different from an SQL database. You must think about your queries before you even create a document. Once you learn the patterns, you can create any structure.

I am still a firm believer that all data is relational!

But, Firebase allows you to create an app faster than any database platform I have used. Firestore is amazing in this aspect.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Inside STL: Waiting for a std::atomic> to change, part 1

1 Share

Like other std::atomic specializations, std::atomic<std::shared_ptr<T>> supports the wait and notify_* methods for waiting for the value to change and reporting that the value has changed. The definition of “changed” in the C++ language specification is that the value has changed if either the stored pointer or the control block pointer has changed. A shared pointer is implemented as a pair of pointers, but Wait­On­Address can wait on at most 8 bytes, and unix futexes can wait on only four bytes, so how does this work?¹

The Microsoft implementation waits for the stored pointer to change, and the notify_* methods signal the stored pointer. But wait, this fails to detect the case where the stored pointer stays the same and only the control block changes.

std::atomic<std::shared_ptr<int>> p =
    std::make_shared<int>(42);

void change_control_block()
{
    auto old = p.load();
    auto empty = std::shared_ptr<int>();

    // Replace with an indulgent shared pointer
    // with the same stored pointer.
    p.store({ empty, old.get() });
    p.notify_all();
}

void wait_for_change()
{
    auto old = p.load();
    p.wait(old);
}

We updated p with a shared_ptr that has the same stored pointer but a different control block. If the stored pointer is the same, how does the p.wait() wake up? The implementation of p.wait() waits for the stored pointer to change, but we didn’t change it.

The answer is that msvc doesn’t wait indefinitely for the pointer to change. It waits with a timeout, and after the timeout, it checks whether either the stored pointer and control block have changed. If so, then the wait() method returns. Otherwise, msvc waits a little more. The wait starts at 16ms and increases exponentially until it caps at around 17 minutes.

So changes that alter only the control block pointer will still notify, thought they might be a little sluggish about it. In practice, there is very little sluggishness because Wake­By­Address­Single and Wake­By­Address­All will wake a Wait­On­Address that has entered the wait state, so the chances for a sluggish wake are rather slim.

lock p
decide to wait
unlock p
prepare for wait ← danger zone
add to wait list
prepare to block (or early-exit)
block thread

It’s only in that danger zone, when the notify_* tries to wake up a thread that hasn’t yet gone to sleep, where you get a sluggish wake.

And you may recall from a peek behind the curtain of Wait­On­Address that the system tries hard to close the gap of the “prepare to wait”, so in practice, the window of sluggishness is quite small.

Next time, we’ll look at the libstdc++ implementation of wait and notify_*. The wild ride continues.

¹ The proposal to add wait and notify_* to std::atomic<std::shared_ptr<T>> merely says that their omission was “due to oversight.” There was no discussion of whether the proposed wait and notify_* methods are actually implementable, seeing as shared pointers are twice the size of normal pointers and may exceed implementation limits for atomic operations. That is merely left as an exercise for the implementation. An exercise that msvc got wrong the first time.

The post Inside STL: Waiting for a <CODE>std::atomic<std::shared_ptr<T>></CODE> to change, part 1 appeared first on The Old New Thing.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete
Next Page of Stories